dummy_hcd.c revision d262127c330b852ce4b210a0b1b06e69d4d87704
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maintainer: Alan Stern <stern@rowland.harvard.edu>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 David Brownell
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003-2005 Alan Stern
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This exposes a device side "USB gadget" API, driven by requests to a
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux-USB host controller driver.  USB traffic is simulated; there's
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no need for USB hardware.  Use this with two other drivers:
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Gadget driver, responding to requests (slave);
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Host-side device driver, as already familiar in Linux.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Having this all in one kernel can help some stages of development,
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bypassing some hardware (and driver) issues.  UML could help too.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
38d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
409454a57ab5922e5cd25321cae9d1a8cbeb3e2e85David Brownell#include <linux/usb/gadget.h>
4127729aadd31dafddaaf64c24f8ef6d0ff750f3aaEric Lescouet#include <linux/usb/hcd.h>
4214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior#include <linux/scatterlist.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC	"USB Host+Gadget Emulator"
52391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION	"02 May 2005"
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern#define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
55caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_name [] = "dummy_hcd";
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_desc [] = "USB Host+Gadget Emulator";
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	gadget_name [] = "dummy_udc";
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell");
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL");
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstruct dummy_hcd_module_parameters {
661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	bool is_super_speed;
677eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	bool is_high_speed;
681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct dummy_hcd_module_parameters mod_data = {
717eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_super_speed = false,
727eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	.is_high_speed = true,
731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman};
741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanmodule_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana BrokhmanMODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
767eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhmanmodule_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
777eca4c5a8b73f22ad16ad6e76b901351732355daTatyana BrokhmanMODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep {
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			last_io;	/* jiffies timestamp */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		*gadget;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usb_endpoint_descriptor *desc;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep			ep;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			halted : 1;
88851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	unsigned			wedged : 1;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			already_seen : 1;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			setup_stage : 1;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request {
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;		/* ep's requests */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_request		req;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_ep, struct dummy_ep, ep);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(struct usb_request *_req)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_req, struct dummy_request, req);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints,
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types:
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Configurable:  direction (in/out), type (bulk, iso, etc), and endpoint
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     number can be changed.  Names like "ep-a" are used for this type.
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Fixed Function:  in other cases.  some characteristics may be mutable;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     that'd be hardware-specific.  Names like "ep12out-bulk" are used.
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on.
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0";
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = {
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep0name,				/* everyone has ep0 */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* act like a net2280: high speed, six configurable endpoints */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like pxa250: fifteen fixed function endpoints */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ep15in-int",
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like sa1100: two fixed function endpoints */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1out-bulk", "ep2in-bulk",
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
14252950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS	ARRAY_SIZE(ep_name)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
144d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
145d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE		64
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp {
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb		*urb;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head	urbp_list;
15114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct sg_mapping_iter	miter;
15214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32			miter_started;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
155391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
156391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state {
157391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RESET,
158391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_SUSPENDED,
159391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RUNNING
160391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern};
161391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
162cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstruct dummy_hcd {
163cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy			*dum;
164cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	enum dummy_rh_state		rh_state;
165cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct timer_list		timer;
166cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				port_status;
167cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	u32				old_status;
168cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned long			re_timeout;
169cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
170cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_device		*udev;
171cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct list_head		urbp_list;
172cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
173cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			active:1;
174cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			old_active:1;
175cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	unsigned			resuming:1;
176cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman};
177cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy {
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t			lock;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE/GADGET side support
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep			ep [DUMMY_ENDPOINTS];
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				address;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		gadget;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget_driver	*driver;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request		fifo_req;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8				fifo_buf [FIFO_SIZE];
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16				devstatus;
191391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned			udc_suspended:1;
192f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			pullup:1;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER/HOST side support
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
197cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd		*hs_hcd;
1981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy_hcd		*ss_hcd;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
203cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return (struct dummy_hcd *) (hcd->hcd_priv);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
206cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of((void *) dum, struct usb_hcd, hcd_priv);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct device *dummy_dev(struct dummy_hcd *dum)
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
213cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return dummy_hcd_to_hcd(dum)->self.controller;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
216d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum)
217d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
218d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return dum->gadget.dev.parent;
219d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
220d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (ep->gadget, struct dummy, gadget);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
226cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
228cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = container_of(gadget, struct dummy, gadget);
2291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER)
2301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->ss_hcd;
2311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	else
2321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dum->hs_hcd;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (dev, struct dummy, gadget.dev);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
240cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic struct dummy			the_controller;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
244f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */
245f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
246f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */
247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep)
248f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	while (!list_empty (&ep->queue)) {
250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		struct dummy_request	*req;
251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req = list_entry (ep->queue.next, struct dummy_request, queue);
253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		list_del_init (&req->queue);
254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.status = -ESHUTDOWN;
255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_unlock (&dum->lock);
257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.complete (&ep->ep, &req->req);
258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_lock (&dum->lock);
259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum)
265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy_ep	*ep;
267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* prevent any more requests */
269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->address = 0;
270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* The timer is left running so that outstanding URBs can fail */
272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* nuke any pending requests first, so driver i/o is quiesced */
274f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
275f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		nuke (dum, ep);
276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* driver now does any non-usb quiescing necessary */
278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
2801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/**
2811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * set_link_state_by_speed() - Sets the current state of the link according to
2821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *	the hcd speed
2831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
2841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman *
2851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * This function updates the port_status according to the link state and the
2861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman * speed of the hcd.
2871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman */
2881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
2891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
2901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct dummy *dum = dum_hcd->dum;
2911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) {
2931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) {
2941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
2951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
2961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
2971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
2981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE);
2991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* device is connected and not suspended */
3051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
3061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						 USB_PORT_STAT_SPEED_5GBPS) ;
3071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status &
3121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_ENABLE) == 1 &&
3131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(dum_hcd->port_status &
3141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 USB_SS_PORT_LS_U0) == 1 &&
3151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
3191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) {
3201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status = 0;
3211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum->pullup || dum->udc_suspended) {
3221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* UDC suspend must cause a disconnect */
3231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
3241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_ENABLE |
3251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_LOW_SPEED |
3261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_HIGH_SPEED |
3271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						USB_PORT_STAT_SUSPEND);
3281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) != 0)
3301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else {
3331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
3341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->old_status &
3351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			     USB_PORT_STAT_CONNECTION) == 0)
3361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |=
3371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_PORT_STAT_C_CONNECTION << 16);
3381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
3391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
3401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else if ((dum_hcd->port_status &
3411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				  USB_PORT_STAT_SUSPEND) == 0 &&
3421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
3431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->active = 1;
3441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
3451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
3461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
3471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
348f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
349cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void set_link_state(struct dummy_hcd *dum_hcd)
350f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
351cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy *dum = dum_hcd->dum;
352cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
353cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->active = 0;
3541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->pullup)
3551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
3561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed != USB_SPEED_SUPER) ||
3571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
3581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		     dum->gadget.speed == USB_SPEED_SUPER))
3591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			return;
3601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
3611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	set_link_state_by_speed(dum_hcd);
362f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
363cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
364cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	     dum_hcd->active)
365cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->resuming = 0;
366f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* if !connected or reset */
368cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
369cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
3701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
3711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * We're connected and not reset (reset occurred now),
3721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * and driver attached - disconnect!
3731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
374cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
3751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
3761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		    dum->driver) {
3771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			stop_activity(dum);
3781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->disconnect(&dum->gadget);
3801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
381f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
382cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->active != dum_hcd->old_active) {
383cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->old_active && dum->driver->suspend) {
3841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->suspend(&dum->gadget);
3861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
3871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
3881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_unlock(&dum->lock);
3891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->driver->resume(&dum->gadget);
3901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			spin_lock(&dum->lock);
391f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
392f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
393f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
394cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_status = dum_hcd->port_status;
395cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->old_active = dum_hcd->active;
396f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
397f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
398f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/
399f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state.  All the work is done when the host
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation.  Real device controller
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc.
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(dum->port_status & USB_PORT_STAT_ENABLE)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
414cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		max;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !desc || ep->desc || _ep->name == ep0name
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| desc->bDescriptorType != USB_DT_ENDPOINT)
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
424cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver)
425cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		return -ESHUTDOWN;
426719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior
427719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
428cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!is_enabled(dum_hcd))
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
430cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
431cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	/*
432cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
433cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 * maximum packet size.
4341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	 * For SS devices the wMaxPacketSize is limited by 1024.
435cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	 */
43629cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto	max = usb_endpoint_maxp(desc) & 0x7ff;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* drivers must not request bad settings, since lower levels
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (hardware or its drivers) may not check.  some endpoints
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't do iso, many have maxpacket limitations, etc.
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since this "hardware" driver is here to help debugging, we
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have some extra sanity checks.  (there could be more though,
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially for "ep9out" style fixed function ones.)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = -EINVAL;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (desc->bmAttributes & 0x03) {
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_BULK:
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int")) {
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (max == 1024)
4561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
4571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto done;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max == 512)
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4619063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4629063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		case USB_SPEED_FULL:
4639063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			if (max == 8 || max == 16 || max == 32 || max == 64)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we'll fake any legal size */
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4669063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			/* save a return statement */
4679063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil		default:
4689063ff44f081a0297085952f6760dfe1f8ca840eIngo van Lil			goto done;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_INT:
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 64)
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 8)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_ISOC:
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-bulk")
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int"))
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_SPEED_SUPER:
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1023)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* few chips support control except on ep0 */
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_ep->maxpacket = max;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = desc;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
518d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_ep->name,
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		desc->bEndpointAddress & 0x0f,
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *val;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (desc->bmAttributes & 0x03) {
5247c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_BULK:
5257c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "bulk";
5267c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5277c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_ISOC:
5287c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "iso";
5297c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5307c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_ENDPOINT_XFER_INT:
5317c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "intr";
5327c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5337c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
5347c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 val = "ctrl";
5357c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			 break;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; val; }),
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		max);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* at this point real hardware should be NAKing transfers
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to that endpoint, until a buffer is queued to it.
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
542851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	ep->halted = ep->wedged = 0;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep)
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !ep->desc || _ep->name == ep0name)
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = NULL;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nuke (dum, ep);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
566d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request *
57155016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5807039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn	req = kzalloc(sizeof(*req), mem_flags);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!req)
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&req->queue);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &req->req;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON (!list_empty (&req->queue));
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (req);
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req)
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6085db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req,
60955016f10e31bb15b85d8c500f979dfdceb37d548Al Viro		gfp_t mem_flags)
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
614cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_req || !list_empty (&req->queue) || !_req->complete)
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
626719e52cbc7b826fae9501f3b86b8cbc25a4c5268Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
627cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum->driver || !is_enabled(dum_hcd))
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
631d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&dum->fifo_req.queue) &&
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&ep->queue) &&
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy (dum->fifo_buf, _req->buf, _req->length);
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
657c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell	}  else
658c728df70ab0dd59b8ccdc3c611ea88925e6697dbDavid Brownell		list_add_tail(&req->queue, &ep->queue);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
683b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_save (flags);
684b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_lock (&dum->lock);
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
693b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_unlock (&dum->lock);
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
696d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		dev_dbg (udc_dev(dum),
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
701b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_restore (flags);
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
706851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
718851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		ep->halted = ep->wedged = 0;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!list_empty (&ep->queue))
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
722851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	else {
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
724851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		if (wedged)
725851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern			ep->wedged = 1;
726851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int
732851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sterndummy_set_halt(struct usb_ep *_ep, int value)
733851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
734851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, value, 0);
735851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
736851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
737851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Sternstatic int dummy_set_wedge(struct usb_ep *_ep)
738851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern{
739851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	if (!_ep || _ep->name == ep0name)
740851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern		return -EINVAL;
741851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	return dummy_set_halt_and_wedge(_ep, 1, 1);
742851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern}
743851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
755851a526dcf97964265cadcc6664a9f0ff7c143c7Alan Stern	.set_wedge	= dummy_set_wedge,
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget)
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday (&tv);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget)
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
771cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
773cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = gadget_to_dummy_hcd(_gadget);
774cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
7755742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
777cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
778391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
779cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
780cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
781391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
782391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
783391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
786cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->resuming = 1;
787cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
788cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
796cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (gadget_to_dummy_hcd(_gadget))->dum;
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
804d262127c330b852ce4b210a0b1b06e69d4d87704Sebastian Andrzej Siewiorstatic void dummy_udc_update_ep0(struct dummy *dum)
805b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior{
806c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	if (dum->gadget.speed == USB_SPEED_SUPER)
807b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 9;
808c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior	else
809b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		dum->ep[0].ep.maxpacket = 64;
810b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior}
811b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
812f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value)
813f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
814d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	struct dummy_hcd *dum_hcd;
815f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
816f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
817f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
818b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	dum = gadget_dev_to_dummy(&_gadget->dev);
819b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
820b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	if (value && dum->driver) {
821b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		if (mod_data.is_super_speed)
8227177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz			dum->gadget.speed = dum->driver->max_speed;
823b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else if (mod_data.is_high_speed)
824b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
8257177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz					dum->driver->max_speed);
826b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior		else
827b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dum->gadget.speed = USB_SPEED_FULL;
828d262127c330b852ce4b210a0b1b06e69d4d87704Sebastian Andrzej Siewior		dummy_udc_update_ep0(dum);
829b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
8307177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz		if (dum->gadget.speed < dum->driver->max_speed)
831b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior			dev_dbg(udc_dev(dum), "This device can perform faster"
8327177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				" if you connect it to a %s port...\n",
8337177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz				usb_speed_string(dum->driver->max_speed));
834b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior	}
835d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	dum_hcd = gadget_to_dummy_hcd(_gadget);
836d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior
837f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
838f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
839d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
840f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
841b5738413c96126e8191bc506b403cd55950b8f9aSebastian Andrzej Siewior
842d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
843f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
844f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
845f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
846aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
847aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
848aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
849aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver);
8500f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
855f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
856aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_start	= dummy_udc_start,
857aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	.udc_stop	= dummy_udc_stop,
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
86410523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf)
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = gadget_dev_to_dummy (dev);
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
872cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
890aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_start(struct usb_gadget *g,
891aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
893aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
894aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8967177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz	if (driver->max_speed == USB_SPEED_UNKNOWN)
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9035742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
907d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
912aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewiorstatic int dummy_udc_stop(struct usb_gadget *g,
913aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior		struct usb_gadget_driver *driver)
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
915aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
916aa0747394337e50533badd46e8fb7106bad3311eSebastian Andrzej Siewior	struct dummy		*dum = dum_hcd->dum;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
918d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
9222542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior
9232542787430fc46b4e07e0da4c6ec80ed230032e5Sebastian Andrzej Siewior	dummy_pullup(&dum->gadget, 0);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
929d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
930d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
931d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
932d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev)
933d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
934cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return;
935d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
936d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9370fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewiorstatic void init_dummy_udc_hw(struct dummy *dum)
9380fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior{
9390fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	int i;
9400fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9410fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->gadget.ep_list);
9420fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
9430fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		struct dummy_ep	*ep = &dum->ep[i];
9440fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9450fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		if (!ep_name[i])
9460fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior			break;
9470fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.name = ep_name[i];
9480fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.ops = &dummy_ep_ops;
9490fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
9500fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->halted = ep->wedged = ep->already_seen =
9510fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior				ep->setup_stage = 0;
9520fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->ep.maxpacket = ~0;
953c688419141ad6134d7973fcf182e3719e98d7491Sebastian Andrzej Siewior		ep->ep.max_streams = 16;
9540fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->last_io = jiffies;
9550fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->gadget = &dum->gadget;
9560fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		ep->desc = NULL;
9570fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior		INIT_LIST_HEAD(&ep->queue);
9580fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	}
9590fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9600fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	dum->gadget.ep0 = &dum->ep[0].ep;
9610fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	list_del_init(&dum->ep[0].ep.ep_list);
9620fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	INIT_LIST_HEAD(&dum->fifo_req.queue);
963f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior
964f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#ifdef CONFIG_USB_OTG
965f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior	dum->gadget.is_otg = 1;
966f8744d40ca12d54f35c56831040683d52e765bf8Sebastian Andrzej Siewior#endif
9670fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior}
9680fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9698364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_probe (struct platform_device *pdev)
970d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
971cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy	*dum = &the_controller;
972d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
973d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
974d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
975d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
976d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz	dum->gadget.max_speed = USB_SPEED_SUPER;
977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9780031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers	dev_set_name(&dum->gadget.dev, "gadget");
9798364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dum->gadget.dev.parent = &pdev->dev;
980d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
981d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	rc = device_register (&dum->gadget.dev);
98275d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	if (rc < 0) {
98375d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar		put_device(&dum->gadget.dev);
984d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
98575d87cdf3cefd2744fabd3f2a558c49cdf36238bRahul Ruikar	}
986d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9870fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior	init_dummy_udc_hw(dum);
9880fb5759952e934dd5ff25fd79f45cb5d69c8d2d1Sebastian Andrzej Siewior
9890f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
9900f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	if (rc < 0)
9910f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_udc;
9920f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
993efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
994efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if (rc < 0)
9950f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		goto err_dev;
9960f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	platform_set_drvdata(pdev, dum);
9970f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	return rc;
9980f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
9990f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_dev:
10000f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10010f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorerr_udc:
10020f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	device_unregister(&dum->gadget.dev);
1003d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
1004d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1005d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10068364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_remove (struct platform_device *pdev)
1007d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
10088364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	struct dummy	*dum = platform_get_drvdata (pdev);
1009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10100f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&dum->gadget);
10118364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	platform_set_drvdata (pdev, NULL);
1012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_remove_file (&dum->gadget.dev, &dev_attr_function);
1013d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_unregister (&dum->gadget.dev);
1014d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
1015d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
1016d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1017fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd,
1018fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior		int suspend)
1019391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1020fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_lock_irq(&dum->lock);
1021fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dum->udc_suspended = suspend;
1022d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	set_link_state(dum_hcd);
1023fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	spin_unlock_irq(&dum->lock);
1024fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior}
1025fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior
1026fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state)
1027fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior{
1028fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1029fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1030391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1031fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1032fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 1);
1033d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1034391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1035391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1036391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1037fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewiorstatic int dummy_udc_resume(struct platform_device *pdev)
1038391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1039fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy		*dum = platform_get_drvdata(pdev);
1040fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
1041391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1042fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dev_dbg(&pdev->dev, "%s\n", __func__);
1043fc0b721f27beb5464d9fb5e521f5cd68127dd14eSebastian Andrzej Siewior	dummy_udc_pm(dum, dum_hcd, 0);
1044d8a14a85c72faf1bdcbbc12255361aaa9cb79ff5Sebastian Andrzej Siewior	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
1045391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1046391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1047391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
10483ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = {
1049d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
1050d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
1051391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
1052391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
10533ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
10543ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) gadget_name,
10553ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
10563ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
1057d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
1058d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue (
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
107655016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t				mem_flags
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1078cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
1081e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp = kmalloc (sizeof *urbp, mem_flags);
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
108714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	urbp->miter_started = 0;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1089cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1090cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1091e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_link_urb_to_ep(hcd, urb);
1092e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	if (rc) {
1093e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		kfree(urbp);
1094e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		goto done;
1095e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	}
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1097cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1098cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = urb->dev;
1099cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_get_dev(dum_hcd->udev);
1100cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (unlikely(dum_hcd->udev != urb->dev))
1101cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1103cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
1109cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!timer_pending(&dum_hcd->timer))
1110cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + 1);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1112e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done:
1113cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1114e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1117e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1119cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
1120391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1121e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
1122391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1123391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1124391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1125cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1126cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1127e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1128e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1129cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
1130cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			!list_empty(&dum_hcd->urbp_list))
1131cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies);
1132e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1133cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
1134e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1137a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewiorstatic int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
1138a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior		u32 len)
1139a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior{
1140a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	void *ubuf, *rbuf;
114114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct urbp *urbp = urb->hcpriv;
1142a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	int to_host;
114314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	struct sg_mapping_iter *miter = &urbp->miter;
114414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32 trans = 0;
114514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	u32 this_sg;
114614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	bool next_sg;
1147a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
1148a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	to_host = usb_pipein(urb->pipe);
1149a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior	rbuf = req->req.buf + req->req.actual;
1150a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
115114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (!urb->num_sgs) {
115214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		ubuf = urb->transfer_buffer + urb->actual_length;
115314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
115414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(ubuf, rbuf, len);
115514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
115614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(rbuf, ubuf, len);
115714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		return len;
115814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
115914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
116014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (!urbp->miter_started) {
116114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		u32 flags = SG_MITER_ATOMIC;
116214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
116314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
116414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			flags |= SG_MITER_TO_SG;
116514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
116614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			flags |= SG_MITER_FROM_SG;
116714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
116814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		sg_miter_start(miter, urb->sg, urb->num_sgs, flags);
116914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		urbp->miter_started = 1;
117014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
117114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	next_sg = sg_miter_next(miter);
117214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	if (next_sg == false) {
117314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		WARN_ON_ONCE(1);
117414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		return -EINVAL;
117514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	}
117614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	do {
117714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		ubuf = miter->addr;
117814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		this_sg = min_t(u32, len, miter->length);
117914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		miter->consumed = this_sg;
118014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		trans += this_sg;
118114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
118214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (to_host)
118314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(ubuf, rbuf, this_sg);
118414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		else
118514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			memcpy(rbuf, ubuf, this_sg);
118614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		len -= this_sg;
118714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
118814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (!len)
118914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			break;
119014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		next_sg = sg_miter_next(miter);
119114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		if (next_sg == false) {
119214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			WARN_ON_ONCE(1);
119314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			return -EINVAL;
119414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		}
119514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
119614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior		rbuf += this_sg;
119714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	} while (1);
119814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior
119914fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	sg_miter_stop(miter);
120014fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	return trans;
1201a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior}
1202a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
12054d2f110c51eec853c50f68cf068888a77551c8d3Alan Sterntransfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
12064d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int *status)
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min (host_len, dev_len);
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_host = usb_pipein (urb->pipe);
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely (len == 0))
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = min (len, (unsigned) limit);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1248a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior			len = dummy_perform_transfer(urb, req, len);
1249a04ce20d9f5e9484ed3879e1290bd05933cbbe2aSebastian Andrzej Siewior
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
125114fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			if (len < 0) {
125214fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				req->req.status = len;
125314fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			} else {
125414fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				limit -= len;
125514fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				urb->actual_length += len;
125614fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior				req->req.actual += len;
125714fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior			}
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
1265b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern		 * need to emulate such data-in-flight.
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12704d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
12744d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = -EOVERFLOW;
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
12764d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern					*status = 0;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
12784d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
12924d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern						& URB_ZERO_PACKET))
12934d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				*status = 0;
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock (&dum->lock);
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.complete (&ep->ep, &req->req);
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock (&dum->lock);
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
13094d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (*status != -EINPROGRESS)
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
132729cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto		tmp = usb_endpoint_maxp(ep->desc);
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->gadget.speed == USB_SPEED_SUPER) {
13331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		switch (ep->desc->bmAttributes & 0x03) {
13341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_ISOC:
13351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.8.2 USB3.0 Spec */
13361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 16 * 1024 * 8;
13371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
13381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_INT:
13391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Sec. 4.4.7.2 USB3.0 Spec */
13401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			limit = 3 * 1024 * 8;
13411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
13421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_ENDPOINT_XFER_BULK:
13431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		default:
13441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
13451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
13461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1350cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman#define is_active(dum_hcd)	((dum_hcd->port_status & \
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
13601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dum->ss_hcd : dum->hs_hcd)))
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return &dum->ep [0];
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13848be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
13858be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman/**
13868be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * handle_control_request() - handles all control transfers
13878be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @dum: pointer to dummy (the_controller)
13888be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @urb: the urb request to handle
13898be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @setup: pointer to the setup data for a USB device control
13908be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	 request
13918be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * @status: pointer to request handling status
13928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *
13938be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman * Return 0 - if the request was handled
13948be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  1 - if the request wasn't handles
13958be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman *	  error code on error
13968be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman */
1397cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
13988be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  struct usb_ctrlrequest *setup,
13998be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				  int *status)
14008be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman{
14018be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	struct dummy_ep		*ep2;
1402cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
14038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	int			ret_val = 1;
14048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_index;
14058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	unsigned	w_value;
14068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
14078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_index = le16_to_cpu(setup->wIndex);
14088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	w_value = le16_to_cpu(setup->wValue);
14098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	switch (setup->bRequest) {
14108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_ADDRESS:
14118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType != Dev_Request)
14128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			break;
14138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dum->address = w_value;
14148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		*status = 0;
14158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		dev_dbg(udc_dev(dum), "set_address = %d\n",
14168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value);
14178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		ret_val = 0;
14188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_SET_FEATURE:
14208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
14218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
14238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
14248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_B_HNP_ENABLE:
14268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.b_hnp_enable = 1;
14278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_HNP_SUPPORT:
14298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_hnp_support = 1;
14308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_A_ALT_HNP_SUPPORT:
14328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->gadget.a_alt_hnp_support = 1;
14338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
14351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
14381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
14421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
14451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
14491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
14521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
14568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
14598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus |= (1 << w_value);
14608be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
14618be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14628be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
14638be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
14648be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
14658be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2 || ep2->ep.name == ep0name) {
14668be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
14678be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14688be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
14698be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2->halted = 1;
14708be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14718be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
14728be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
14738be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
14748be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_CLEAR_FEATURE:
14758be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_Request) {
14768be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
14778be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			switch (w_value) {
14788be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			case USB_DEVICE_REMOTE_WAKEUP:
14798be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				w_value = USB_DEVICE_REMOTE_WAKEUP;
14808be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
14811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U1_ENABLE:
14821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U1_ENABLED;
14851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_U2_ENABLE:
14891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_U2_ENABLED;
14921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
14931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
14941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
14951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			case USB_DEVICE_LTM_ENABLE:
14961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
14971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				    HCD_USB3)
14981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					w_value = USB_DEV_STAT_LTM_ENABLED;
14991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				else
15001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					ret_val = -EOPNOTSUPP;
15011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				break;
15028be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			default:
15038be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
15048be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15058be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15068be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (ret_val == 0) {
15078be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				dum->devstatus &= ~(1 << w_value);
15088be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				*status = 0;
15098be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15108be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		} else if (setup->bRequestType == Ep_Request) {
15118be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/* endpoint halt */
15128be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ep2 = find_endpoint(dum, w_index);
15138be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2) {
15148be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ret_val = -EOPNOTSUPP;
15158be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				break;
15168be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15178be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (!ep2->wedged)
15188be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				ep2->halted = 0;
15198be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15208be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
15218be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
15228be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
15238be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	case USB_REQ_GET_STATUS:
15248be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		if (setup->bRequestType == Dev_InRequest
15258be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Intf_InRequest
15268be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				|| setup->bRequestType == Ep_InRequest) {
15278be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			char *buf;
15288be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			/*
15298be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * device: remote wakeup, selfpowered
15308be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * interface: nothing
15318be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 * endpoint: halt
15328be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			 */
15338be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			buf = (char *)urb->transfer_buffer;
15348be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 0) {
15358be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				if (setup->bRequestType == Ep_InRequest) {
15368be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					ep2 = find_endpoint(dum, w_index);
15378be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					if (!ep2) {
15388be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						ret_val = -EOPNOTSUPP;
15398be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						break;
15408be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					}
15418be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = ep2->halted;
15428be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else if (setup->bRequestType ==
15438be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					   Dev_InRequest) {
15448be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = (u8)dum->devstatus;
15458be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				} else
15468be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman					buf[0] = 0;
15478be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			}
15488be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			if (urb->transfer_buffer_length > 1)
15498be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				buf[1] = 0;
15508be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			urb->actual_length = min_t(u32, 2,
15518be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman				urb->transfer_buffer_length);
15528be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			ret_val = 0;
15538be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman			*status = 0;
15548be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		}
15558be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman		break;
15568be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	}
15578be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman	return ret_val;
15588be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman}
15598be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1563cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic void dummy_timer(unsigned long _dum_hcd)
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1565cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
1566cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum = dum_hcd->dum;
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case USB_SPEED_SUPER:
15841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* Bus speed is 500000 bytes/ms, so use a little less */
15851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		total = 490000;
15861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1588cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1597cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!dum_hcd->udev) {
1598cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_err(dummy_dev(dum_hcd),
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&dum->lock, flags);
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->ep [i].already_seen = 0;
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
1611cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
16174d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		int			status = -EINPROGRESS;
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
1620eb23105462304fd35571fd0cab1de7aec79a9ec5Alan Stern		if (urb->unlinked)
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1622cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
1623391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = usb_pipetype (urb->pipe);
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (usb_pipein (urb->pipe))
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
1640cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
16434d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPROTO;
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && urb->error_count) {
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
1656cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
16584d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -EPIPE;
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && ep->setup_stage) {
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_for_each_entry (req, &ep->queue, queue) {
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				list_del_init (&req->queue);
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
1673d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "stale req = %p\n",
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.complete (&ep->ep, &req->req);
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			value = handle_control_request(dum_hcd, urb, &setup,
16928be8a9d3d16a25645b7869e4544a9d0ec386966aTatyana Brokhman						       &status);
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = dum->driver->setup (&dum->gadget,
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
1713d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern					dev_dbg (udc_dev(dum),
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
17164d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern				status = -EPIPE;
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (usb_pipetype (urb->pipe)) {
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
17334d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			status = -ENOSYS;
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// case PIPE_BULK:  case PIPE_CONTROL:
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		treat_control_like_bulk:
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
17474d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern			total = transfer(dum, urb, ep, limit, &status);
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
17524d2f110c51eec853c50f68cf068888a77551c8d3Alan Stern		if (status == -EINPROGRESS)
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del (&urbp->urbp_list);
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (urbp);
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
1763cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1769cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (list_empty(&dum_hcd->urbp_list)) {
1770cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_dev(dum_hcd->udev);
1771cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->udev = NULL;
1772cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
1773391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1774cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1783c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1784c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1785c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1786c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1787c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf)
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1791cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1793391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1795cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1797cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
1798541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1799391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1800f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1801cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
1802cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1803cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
1804cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1805f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1806f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1807cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
1809cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
1810cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status);
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1812cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
1813391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			usb_hcd_resume_root_hub (hcd);
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1815391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
1816cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
18211cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanss_hub_descriptor(struct usb_hub_descriptor *desc)
18221cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
18231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	memset(desc, 0, sizeof *desc);
18241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescriptorType = 0x2a;
18251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bDescLength = 12;
18261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->wHubCharacteristics = cpu_to_le16(0x0001);
18271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->bNbrPorts = 1;
18281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
18291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	desc->u.ss.DeviceRemovable = 0xffff;
18301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
18311cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
18321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic inline void
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc)
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (desc, 0, sizeof *desc);
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1838fd05e720099e8eeddb378305d1a41c1445344b91Al Viro	desc->wHubCharacteristics = cpu_to_le16(0x0001);
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
1840dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[0] = 0xff;
1841dbe79bbe9dcb22cb3651c46f18943477141ca452John Youn	desc->u.hs.DeviceRemovable[1] = 0xff;
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control (
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
1852cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd;
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1856541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd))
1857391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1858391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1859cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
1860cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
1861cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
18681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
18691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
18701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
18711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
18721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
18731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1874cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
1876cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->resuming = 1;
1877cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->re_timeout = jiffies +
1878f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
18821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
18831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
18841cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
18851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
18861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
18871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (dum_hcd->port_status &
18881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SS_PORT_STAT_POWER)
18891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
18901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						"power-off\n");
1891f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1893cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~(1 << wValue);
1894cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
18981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3 &&
18991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				(wLength < USB_DT_SS_HUB_SIZE ||
19001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 wValue != (USB_DT_SS_HUB << 8))) {
19011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
19021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"Wrong hub descriptor type for "
19031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				"USB 3.0 roothub.\n");
19041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
19051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
19061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed == HCD_USB3)
19071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
19081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		else
19091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			hub_descriptor((struct usb_hub_descriptor *) buf);
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
1912551509d267905705f6d723e51ec706916f06b859Harvey Harrison		*(__le32 *) buf = cpu_to_le32 (0);
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1921cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (dum_hcd->resuming &&
1922cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
1923cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1924cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1926cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
1927cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				time_after_eq(jiffies, dum_hcd->re_timeout)) {
1928cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
1929cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
1930cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->dum->pullup) {
1931cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
19321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
19331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if (hcd->speed < HCD_USB3) {
19341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					switch (dum_hcd->dum->gadget.speed) {
19351cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_HIGH:
19361cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
19371cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						      USB_PORT_STAT_HIGH_SPEED;
19381cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
19391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					case USB_SPEED_LOW:
19401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.ep0->
19411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							maxpacket = 8;
19421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->port_status |=
19431cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_PORT_STAT_LOW_SPEED;
19441cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
19451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					default:
19461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						dum_hcd->dum->gadget.speed =
19471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman							USB_SPEED_FULL;
19481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman						break;
19491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					}
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1953cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
1954cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
1955cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
19621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_LINK_STATE:
19631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_LINK_STATE req not "
19661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
19701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * Since this is dummy we don't have an actual link so
19711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * there is nothing to do for the SET_LINK_STATE cmd
19721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
19731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
19741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U1_TIMEOUT:
19751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_U2_TIMEOUT:
19761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* TODO: add suspend/resume support! */
19771cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
19781cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
19801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
19811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
19831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
19851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB2.0 hub */
19861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
19871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
19881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_SUSPEND req not "
19891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 3.0 roothub\n");
19901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
19911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
1992cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			if (dum_hcd->active) {
1993cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
1994f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1995f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
1996f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
1997f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
1998cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				set_link_state(dum_hcd);
1999f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
2000cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman						& dum_hcd->dum->devstatus) != 0)
2001cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman					dev_dbg(dummy_dev(dum_hcd),
20025742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2005f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
20061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3)
20071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
20081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			else
20091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status |= USB_PORT_STAT_POWER;
2010cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			set_link_state(dum_hcd);
2011f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
20121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		case USB_PORT_FEAT_BH_PORT_RESET:
20131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* Applicable only for USB3.0 hub */
20141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed != HCD_USB3) {
20151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dev_dbg(dummy_dev(dum_hcd),
20161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "USB_PORT_FEAT_BH_PORT_RESET req not "
20171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 "supported for USB 2.0 roothub\n");
20181cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				goto error;
20191cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			}
20201cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/* FALLS THROUGH */
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
2022f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
20231cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
20241cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status = 0;
20251cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status =
20261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					(USB_SS_PORT_STAT_POWER |
20271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_CONNECTION |
20281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					 USB_PORT_STAT_RESET);
20291cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
20301cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
2031f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
2032f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
2033cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			/*
2034cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * We want to reset device status. All but the
2035cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 * Self powered feature
2036cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			 */
2037cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->dum->devstatus &=
2038cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman				(1 << USB_DEVICE_SELF_POWERED);
20391cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			/*
20401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * FIXME USB3.0: what is the correct reset signaling
20411cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 * interval? Is it still 50msec as for HS?
20421cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			 */
2043cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
2044f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
20461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			if (hcd->speed == HCD_USB3) {
20471cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
20481cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_SS_PORT_STAT_POWER) != 0) {
20491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
20501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
20511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
20521cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			} else
20531cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				if ((dum_hcd->port_status &
20541cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				     USB_PORT_STAT_POWER) != 0) {
20551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dum_hcd->port_status |= (1 << wValue);
20561cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					set_link_state(dum_hcd);
20571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				}
20581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
20601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case GetPortErrorCount:
20611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
20621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "GetPortErrorCount req not "
20641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "supported for USB 2.0 roothub\n");
20651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
20671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/* We'll always return 0 since this is a dummy hub */
20681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		*(__le32 *) buf = cpu_to_le32(0);
20691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		break;
20701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	case SetHubDepth:
20711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (hcd->speed != HCD_USB3) {
20721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			dev_dbg(dummy_dev(dum_hcd),
20731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "SetHubDepth req not supported for "
20741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman				 "USB 2.0 roothub\n");
20751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto error;
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2079cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dev_dbg(dummy_dev(dum_hcd),
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
20821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanerror:
20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2086cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
2087685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
2088cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
2089685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern		usb_hcd_poll_rh_status (hcd);
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20930c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd)
2094391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2095cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
2096391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2097441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
20983cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2099cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2100cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
2101cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	set_link_state(dum_hcd);
21023cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd->state = HC_STATE_SUSPENDED;
2103cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
2104391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2105391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2106391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
21070c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd)
2108391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2109cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
21103cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int rc = 0;
21113cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
2112441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
2113391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2114cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irq(&dum_hcd->dum->lock);
2115541c7d432f76771079e7c295d596ea47cc6a3030Alan Stern	if (!HCD_HW_ACCESSIBLE(hcd)) {
2116cfa59dab27d1b282886e7772a8f9548236883892Alan Stern		rc = -ESHUTDOWN;
21173cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else {
2118cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		dum_hcd->rh_state = DUMMY_RH_RUNNING;
2119cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		set_link_state(dum_hcd);
2120cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		if (!list_empty(&dum_hcd->urbp_list))
2121cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman			mod_timer(&dum_hcd->timer, jiffies);
21223cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		hcd->state = HC_STATE_RUNNING;
21233cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	}
2124cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irq(&dum_hcd->dum->lock);
21253cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2126391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb)
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ep = usb_pipeendpoint (urb->pipe);
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf (buf, size,
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (urb->dev->speed) {
21407c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_LOW:
21417c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "ls";
21427c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21437c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_FULL:
21447c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "fs";
21457c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21467c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case USB_SPEED_HIGH:
21477c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "hs";
21487c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21491cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 case USB_SPEED_SUPER:
21501cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			s = "ss";
21511cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			break;
21527c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default:
21537c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "?";
21547c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break;
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (usb_pipetype (urb->pipe)) { \
21597c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_CONTROL: \
21607c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = ""; \
21617c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21627c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_BULK: \
21637c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-bulk"; \
21647c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21657c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 case PIPE_INTERRUPT: \
21667c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-int"; \
21677c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21687c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman		 default: \
21697c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			s = "-iso"; \
21707c884fe4d74d17efc83b19f3dc898a75f03859e9Tatyana Brokhman			break; \
21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}; s;}),
21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
217610523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf)
21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd = dev_get_drvdata (dev);
2179cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2184cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2185cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2192cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic int dummy_start_ss(struct dummy_hcd *dum_hcd)
21991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	init_timer(&dum_hcd->timer);
22011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.function = dummy_timer;
22021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
22031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
22041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
22051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
22061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
22071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
22081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#ifdef CONFIG_USB_OTG
22091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
22101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman#endif
22111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
22121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
22131cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
22141cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
22151cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
22161cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2217cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_start(struct usb_hcd *hcd)
22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2219cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
22261cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!usb_hcd_is_primary_hcd(hcd))
22271cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return dummy_start_ss(dum_hcd);
22281cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2229cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	spin_lock_init(&dum_hcd->dum->lock);
2230cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	init_timer(&dum_hcd->timer);
2231cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.function = dummy_timer;
2232cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->timer.data = (unsigned long)dum_hcd;
2233cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd->rh_state = DUMMY_RH_RUNNING;
22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2235cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	INIT_LIST_HEAD(&dum_hcd->urbp_list);
22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2237caf29f62655e7aa57996821535d11fa3b0537b6bAlan Stern	hcd->power_budget = POWER_BUDGET;
22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
2239685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22415742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
22425742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
22435742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
22445742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
2246cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd)
22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2253cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(hcd))->dum;
2254cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
2255cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_gadget_unregister_driver(dum->driver);
2256cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd)
22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_g_get_frame (NULL);
22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2266cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_setup(struct usb_hcd *hcd)
2267cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman{
226814fce33a960afbcf91ef97135903092c33f6d076Sebastian Andrzej Siewior	hcd->self.sg_tablesize = ~0;
2269cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (usb_hcd_is_primary_hcd(hcd)) {
2270cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
2271cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		the_controller.hs_hcd->dum = &the_controller;
22721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		/*
22731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * Mark the first roothub as being USB 2.0.
22741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * The USB 3.0 roothub will be registered later by
22751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 * dummy_hcd_probe()
22761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		 */
2277cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->speed = HCD_USB2;
2278cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_HIGH;
22791cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	} else {
22801cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
22811cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		the_controller.ss_hcd->dum = &the_controller;
22821cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->speed = HCD_USB3;
22831cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		hcd->self.root_hub->speed = USB_SPEED_SUPER;
2284cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	}
2285cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	return 0;
2286cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman}
2287cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
22881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Change a group of bulk endpoints to support multiple stream IDs */
22891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
22901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
22911cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	unsigned int num_streams, gfp_t mem_flags)
22921cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
22931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (hcd->speed != HCD_USB3)
22941cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
22951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			"%s() - ERROR! Not supported for USB2.0 roothub\n",
22961cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			__func__);
22971cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
22981cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
22991cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23001cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman/* Reverts a group of bulk endpoints back to not using stream IDs. */
23011cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanint dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
23021cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_host_endpoint **eps, unsigned int num_eps,
23031cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	gfp_t mem_flags)
23041cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman{
23051cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (hcd->speed != HCD_USB3)
23061cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
23071cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			"%s() - ERROR! Not supported for USB2.0 roothub\n",
23081cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			__func__);
23091cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
23101cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman}
23111cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23121cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanstatic struct hc_driver dummy_hcd = {
23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
2315cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.hcd_priv_size =	sizeof(struct dummy_hcd),
23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23171cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.flags =		HCD_USB3 | HCD_SHARED,
23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2319cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	.reset =		dummy_setup,
23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_enqueue = 		dummy_urb_enqueue,
23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_dequeue = 		dummy_urb_dequeue,
23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame_number = 	dummy_h_get_frame,
23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_status_data = 	dummy_hub_status,
23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_control = 		dummy_hub_control,
23300c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_suspend =		dummy_bus_suspend,
23310c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_resume =		dummy_bus_resume,
23321cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23331cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.alloc_streams =	dummy_alloc_streams,
23341cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	.free_streams =		dummy_free_streams,
23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23378364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev)
23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2339cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct usb_hcd		*hs_hcd;
23401cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	struct usb_hcd		*ss_hcd;
23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23438364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23451cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!mod_data.is_super_speed)
23461cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		dummy_hcd.flags = HCD_USB2;
2347cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
2348cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (!hs_hcd)
23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2350cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	hs_hcd->has_tt = 1;
23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2352cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	retval = usb_add_hcd(hs_hcd, 0, 0);
23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
2354cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman		usb_put_hcd(hs_hcd);
23551cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		return retval;
23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23571cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23581cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (mod_data.is_super_speed) {
23591cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
23601cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman					dev_name(&pdev->dev), hs_hcd);
23611cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (!ss_hcd) {
23621cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			retval = -ENOMEM;
23631cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto dealloc_usb2_hcd;
23641cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		}
23651cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23661cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		retval = usb_add_hcd(ss_hcd, 0, 0);
23671cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		if (retval)
23681cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman			goto put_usb3_hcd;
23691cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
23701cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	return 0;
23711cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23721cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmanput_usb3_hcd:
23731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(ss_hcd);
23741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhmandealloc_usb2_hcd:
23751cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	usb_put_hcd(hs_hcd);
23761cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2380cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhmanstatic int dummy_hcd_remove(struct platform_device *pdev)
23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2382cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy		*dum;
2383cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman
2384cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
23851cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
23861cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (dum->ss_hcd) {
23871cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
23881cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
23891cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	}
23901cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2391cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2392cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
23931cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman
2394cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	the_controller.hs_hcd = NULL;
23951cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	the_controller.ss_hcd = NULL;
23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2397d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24008364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
2401391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2402391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2403cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	struct dummy_hcd	*dum_hcd;
24043cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int			rc = 0;
2405391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2406441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2407391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
24083cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
2409cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	dum_hcd = hcd_to_dummy_hcd(hcd);
2410cdfcbd2c4a9e866c19bf8fe2b4e011a12441c32aTatyana Brokhman	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
24113cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
24123cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		rc = -EBUSY;
24133cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else
24143cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
24153cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
2416391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2417391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
24188364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_resume (struct platform_device *pdev)
2419391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
2420391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
2421391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
2422441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison	dev_dbg (&pdev->dev, "%s\n", __func__);
2423391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
24243cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
24253cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
2426391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (hcd);
2427391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
2428391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
2429391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
24303ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = {
2431d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
2432d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
2433391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
2434391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
24353ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
24363ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) driver_name,
24373ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
24383ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2439d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2443a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_udc_pdev;
2444a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternstatic struct platform_device *the_hcd_pdev;
24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void)
24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2448a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	int	retval = -ENOMEM;
24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_disabled ())
24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2452d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
24537eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman	if (!mod_data.is_high_speed && mod_data.is_super_speed)
24547eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman		return -EINVAL;
24557eca4c5a8b73f22ad16ad6e76b901351732355daTatyana Brokhman
2456a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_hcd_pdev = platform_device_alloc(driver_name, -1);
2457a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_hcd_pdev)
24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
2459a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	the_udc_pdev = platform_device_alloc(gadget_name, -1);
2460a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (!the_udc_pdev)
2461a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_alloc_udc;
2462d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2463a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_hcd_driver);
2464a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	if (retval < 0)
2465a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_register_hcd_driver;
2466a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_driver_register(&dummy_udc_driver);
2467d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2468d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2469d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2470a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_hcd_pdev);
2471d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2472a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_hcd;
24731cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	if (!the_controller.hs_hcd ||
24741cd8fd2887e162ad3d067150962cc3d32dcf3150Tatyana Brokhman	    (!the_controller.ss_hcd && mod_data.is_super_speed)) {
2475865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2476865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The hcd was added successfully but its probe function failed
2477865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2478865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2479865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2480865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_add_udc;
2481865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2482a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	retval = platform_device_add(the_udc_pdev);
2483d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2484a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern		goto err_add_udc;
2485865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	if (!platform_get_drvdata(the_udc_pdev)) {
2486865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		/*
2487865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * The udc was added successfully but its probe function failed
2488865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 * for some reason.
2489865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		 */
2490865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		retval = -EINVAL;
2491865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior		goto err_probe_udc;
2492865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	}
2493d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2494d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2495865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewiorerr_probe_udc:
2496865835fa441fcabc65251f14280df3055fe82d0fSebastian Andrzej Siewior	platform_device_del(the_udc_pdev);
2497a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_udc:
2498a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_del(the_hcd_pdev);
2499a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_add_hcd:
2500a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2501d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
2502a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
2503a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_register_hcd_driver:
2504a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_udc_pdev);
2505a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Sternerr_alloc_udc:
2506a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_put(the_hcd_pdev);
25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init);
25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void)
25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2513a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_udc_pdev);
2514a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_device_unregister(the_hcd_pdev);
2515a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_udc_driver);
2516a89a2cd396b20c46a37fa8db4b652fb00f29d0a4Alan Stern	platform_driver_unregister(&dummy_hcd_driver);
25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup);
2519