dummy_hcd.c revision 391eca9d8892a940ff8dbfee2ca78942e05c2d37
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 * This program is distributed in the hope that it will be useful,
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This exposes a device side "USB gadget" API, driven by requests to a
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux-USB host controller driver.  USB traffic is simulated; there's
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no need for USB hardware.  Use this with two other drivers:
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Gadget driver, responding to requests (slave);
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  - Host-side device driver, as already familiar in Linux.
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Having this all in one kernel can help some stages of development,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bypassing some hardware (and driver) issues.  UML could help too.
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp_lock.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/version.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb_gadget.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../core/hcd.h"
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC	"USB Host+Gadget Emulator"
68391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION	"02 May 2005"
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_name [] = "dummy_hcd";
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_desc [] = "USB Host+Gadget Emulator";
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	gadget_name [] = "dummy_udc";
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell");
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL");
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep {
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			last_io;	/* jiffies timestamp */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		*gadget;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usb_endpoint_descriptor *desc;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep			ep;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			halted : 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};
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DUMMY_ENDPOINTS	(sizeof(ep_name)/sizeof(char *))
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;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
154391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state {
155391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RESET,
156391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_SUSPENDED,
157391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RUNNING
158391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern};
159391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy {
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t			lock;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE/GADGET side support
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep			ep [DUMMY_ENDPOINTS];
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				address;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		gadget;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget_driver	*driver;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request		fifo_req;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8				fifo_buf [FIFO_SIZE];
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16				devstatus;
173391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned			udc_suspended:1;
174f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			pullup:1;
175f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			active:1;
176f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			old_active:1;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER/HOST side support
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
181391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	enum dummy_rh_state		rh_state;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timer_list		timer;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32				port_status;
184f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	u32				old_status;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			resuming:1;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			re_timeout;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_device		*udev;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		urbp_list;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd)
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (struct dummy *) (hcd->hcd_priv);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct usb_hcd *dummy_to_hcd (struct dummy *dum)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of((void *) dum, struct usb_hcd, hcd_priv);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct device *dummy_dev (struct dummy *dum)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_to_hcd(dum)->self.controller;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum)
208d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
209d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return dum->gadget.dev.parent;
210d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
211d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (ep->gadget, struct dummy, gadget);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (gadget, struct dummy, gadget);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (dev, struct dummy, gadget.dev);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy			*the_controller;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */
232f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
233f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */
234f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep)
235f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
236f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	while (!list_empty (&ep->queue)) {
237f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		struct dummy_request	*req;
238f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
239f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req = list_entry (ep->queue.next, struct dummy_request, queue);
240f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		list_del_init (&req->queue);
241f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.status = -ESHUTDOWN;
242f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
243f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_unlock (&dum->lock);
244f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.complete (&ep->ep, &req->req);
245f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_lock (&dum->lock);
246f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
248f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum)
252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy_ep	*ep;
254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* prevent any more requests */
256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->address = 0;
257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* The timer is left running so that outstanding URBs can fail */
259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* nuke any pending requests first, so driver i/o is quiesced */
261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		nuke (dum, ep);
263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* driver now does any non-usb quiescing necessary */
265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
268f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
269f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternset_link_state (struct dummy *dum)
270f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->active = 0;
272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status = 0;
274391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
275391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* UDC suspend must cause a disconnect */
276391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	else if (!dum->pullup || dum->udc_suspended) {
277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					USB_PORT_STAT_ENABLE |
279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					USB_PORT_STAT_LOW_SPEED |
280f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					USB_PORT_STAT_HIGH_SPEED |
281f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					USB_PORT_STAT_SUSPEND);
282f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
283f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
284f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	} else {
285f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status |= USB_PORT_STAT_CONNECTION;
286f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
287f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
288f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
289f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
290391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
291391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern				dum->rh_state != DUMMY_RH_SUSPENDED)
292f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->active = 1;
293f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
294f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
295f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
296f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->resuming = 0;
297f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
298f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
299f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
300f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
301f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
302f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				dum->driver) {
303f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			stop_activity (dum);
304f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_unlock (&dum->lock);
305f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->driver->disconnect (&dum->gadget);
306f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_lock (&dum->lock);
307f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
308f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	} else if (dum->active != dum->old_active) {
309f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if (dum->old_active && dum->driver->suspend) {
310f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_unlock (&dum->lock);
311f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->driver->suspend (&dum->gadget);
312f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_lock (&dum->lock);
313f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		} else if (!dum->old_active && dum->driver->resume) {
314f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_unlock (&dum->lock);
315f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->driver->resume (&dum->gadget);
316f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_lock (&dum->lock);
317f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
318f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
319f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
320f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->old_status = dum->port_status;
321f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->old_active = dum->active;
322f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
323f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
324f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/
325f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state.  All the work is done when the host
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation.  Real device controller
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc.
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(dum->port_status & USB_PORT_STAT_ENABLE)
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		max;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !desc || ep->desc || _ep->name == ep0name
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| desc->bDescriptorType != USB_DT_ENDPOINT)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !is_enabled (dum))
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* drivers must not request bad settings, since lower levels
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (hardware or its drivers) may not check.  some endpoints
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't do iso, many have maxpacket limitations, etc.
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since this "hardware" driver is here to help debugging, we
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have some extra sanity checks.  (there could be more though,
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially for "ep9out" style fixed function ones.)
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = -EINVAL;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (desc->bmAttributes & 0x03) {
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_BULK:
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int")) {
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max == 512)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* conserve return statements */
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (max) {
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 8: case 16: case 32: case 64:
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we'll fake any legal size */
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_LOW:
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto done;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_INT:
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 64)
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 8)
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_ISOC:
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-bulk")
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int"))
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1023)
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* few chips support control except on ep0 */
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_ep->maxpacket = max;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = desc;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
429d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_ep->name,
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		desc->bEndpointAddress & 0x0f,
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *val;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (desc->bmAttributes & 0x03) {
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_ENDPOINT_XFER_BULK: val = "bulk"; break;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_ENDPOINT_XFER_ISOC: val = "iso"; break;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_ENDPOINT_XFER_INT: val = "intr"; break;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 default: val = "ctrl"; break;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; val; }),
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		max);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* at this point real hardware should be NAKing transfers
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to that endpoint, until a buffer is queued to it.
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !ep->desc || _ep->name == ep0name)
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = NULL;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nuke (dum, ep);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
468d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request *
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_alloc_request (struct usb_ep *_ep, int mem_flags)
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = kmalloc (sizeof *req, mem_flags);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!req)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (req, 0, sizeof *req);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&req->queue);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &req->req;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON (!list_empty (&req->queue));
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (req);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void *
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_alloc_buffer (
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep *_ep,
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned bytes,
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t *dma,
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mem_flags
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char			*retval;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = kmalloc (bytes, mem_flags);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*dma = (dma_addr_t) retval;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_buffer (
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep *_ep,
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *buf,
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t dma,
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned bytes
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bytes)
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (buf);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req)
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags)
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_req || !list_empty (&req->queue) || !_req->complete)
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !is_enabled (dum))
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
563d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&dum->fifo_req.queue) &&
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&ep->queue) &&
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy (dum->fifo_buf, _req->buf, _req->length);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail (&req->queue, &ep->queue);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
626d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		dev_dbg (udc_dev(dum),
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_set_halt (struct usb_ep *_ep, int value)
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 0;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!list_empty (&ep->queue))
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_buffer	= dummy_alloc_buffer,
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_buffer	= dummy_free_buffer,
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* map, unmap, ... eventually hook the "generic" dma calls */
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget)
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday (&tv);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget)
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = gadget_to_dummy (_gadget);
690391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE)
6915742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
693391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
694391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
695391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
696391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			 dum->rh_state != DUMMY_RH_SUSPENDED)
697391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
698391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
699391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->resuming = 1;
703f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->re_timeout = jiffies + msecs_to_jiffies(20);
704685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = gadget_to_dummy (_gadget);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
720f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value)
721f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
722f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
723f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
724f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
725f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum = gadget_to_dummy (_gadget);
726f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
727f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
728f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
729f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
730685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
731685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
732f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
733f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
734f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
739f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
74610523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf)
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = gadget_dev_to_dummy (dev);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
754cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_register_driver (struct usb_gadget_driver *driver)
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = the_controller;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval, i;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum)
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->driver)
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!driver->bind || !driver->unbind || !driver->setup
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| driver->speed == USB_SPEED_UNKNOWN)
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7905742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&dum->gadget.ep_list);
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.name = ep_name [i];
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.ops = &dummy_ep_ops;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = ep->already_seen = ep->setup_stage = 0;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.maxpacket = ~0;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->last_io = jiffies;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->gadget = &dum->gadget;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->desc = NULL;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		INIT_LIST_HEAD (&ep->queue);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->gadget.ep0 = &dum->ep [0].ep;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->ep [0].ep.maxpacket = 64;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del_init (&dum->ep [0].ep.ep_list);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&dum->fifo_req.queue);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->gadget.dev.driver = &driver->driver;
817d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((retval = driver->bind (&dum->gadget)) != 0) {
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->driver = NULL;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->gadget.dev.driver = NULL;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->driver.bus = dum->gadget.dev.parent->bus;
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_register (&driver->driver);
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_bind_driver (&dum->gadget.dev);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* khubd will enumerate this in a while */
830f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irq (&dum->lock);
831f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 1;
832f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
833f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irq (&dum->lock);
834685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
835685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_register_driver);
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_unregister_driver (struct usb_gadget_driver *driver)
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = the_controller;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum)
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!driver || driver != dum->driver)
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
855f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 0;
856f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->unbind (&dum->gadget);
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_release_driver (&dum->gadget.dev);
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_unregister (&driver->driver);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
865f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
866f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 0;
867f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
868f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
869f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
870685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_unregister_driver);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
877cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern/* just declare this in any driver that really need it */
878cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternextern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
879cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOSYS;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (net2280_set_fifo_mode);
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
886d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
887d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
888d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
889d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
890d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev)
891d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
892d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern#if 0		/* usb_bus_put isn't EXPORTed! */
893d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	struct dummy	*dum = gadget_dev_to_dummy (dev);
894d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
895d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	usb_bus_put (&dummy_to_hcd (dum)->self);
896d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern#endif
897d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
898d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
899d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic int dummy_udc_probe (struct device *dev)
900d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
901d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	struct dummy	*dum = the_controller;
902d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
903d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
904d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
905d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
906d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.is_dualspeed = 1;
907d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
908d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	/* maybe claim OTG support, though we won't complete HNP */
909d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
910d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
911d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	strcpy (dum->gadget.dev.bus_id, "gadget");
912d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.parent = dev;
913d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
914d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	rc = device_register (&dum->gadget.dev);
915d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (rc < 0)
916d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
917d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
918d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern#if 0		/* usb_bus_get isn't EXPORTed! */
919d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	usb_bus_get (&dummy_to_hcd (dum)->self);
920d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern#endif
921d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
922d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_set_drvdata (dev, dum);
923d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_create_file (&dum->gadget.dev, &dev_attr_function);
924d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
925d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
926d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
927d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic int dummy_udc_remove (struct device *dev)
928d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
929d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	struct dummy	*dum = dev_get_drvdata (dev);
930d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
931d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_set_drvdata (dev, NULL);
932d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_remove_file (&dum->gadget.dev, &dev_attr_function);
933d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_unregister (&dum->gadget.dev);
934d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
935d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
936d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
937391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternstatic int dummy_udc_suspend (struct device *dev, pm_message_t state,
938391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		u32 level)
939391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
940391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy	*dum = dev_get_drvdata(dev);
941391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
942391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (level != SUSPEND_DISABLE)
943391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return 0;
944391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
945391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev_dbg (dev, "%s\n", __FUNCTION__);
946391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
947391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->udc_suspended = 1;
948391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
949391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
950391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
951391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev->power.power_state = state;
952391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
953391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
954391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
955391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
956391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternstatic int dummy_udc_resume (struct device *dev, u32 level)
957391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
958391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy	*dum = dev_get_drvdata(dev);
959391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
960391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (level != RESUME_ENABLE)
961391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return 0;
962391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
963391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev_dbg (dev, "%s\n", __FUNCTION__);
964391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
965391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->udc_suspended = 0;
966391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
967391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
968391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
969391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev->power.power_state = PMSG_ON;
970391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
971391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
972391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
973391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
974d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct device_driver dummy_udc_driver = {
975d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) gadget_name,
976d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.bus		= &platform_bus_type,
977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
978d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
979391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
980391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
981d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
982d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue (
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_host_endpoint	*ep,
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				mem_flags
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urb->transfer_buffer && urb->transfer_buffer_length)
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp = kmalloc (sizeof *urbp, mem_flags);
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->udev) {
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->udev = urb->dev;
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_get_dev (dum->udev);
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (unlikely (dum->udev != urb->dev))
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum), "usb_device address has changed!\n");
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail (&urbp->urbp_list, &dum->urbp_list);
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!timer_pending (&dum->timer))
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mod_timer (&dum->timer, jiffies + 1);
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1039391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy	*dum;
1040391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1041391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1042391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1043391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1044391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum = hcd_to_dummy (hcd);
1045391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irqsave (&dum->lock, flags);
1046391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
1047391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		mod_timer (&dum->timer, jiffies);
1048391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irqrestore (&dum->lock, flags);
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void maybe_set_status (struct urb *urb, int status)
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock (&urb->lock);
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (urb->status == -EINPROGRESS)
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->status = status;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock (&urb->lock);
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstransfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min (host_len, dev_len);
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_host = usb_pipein (urb->pipe);
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely (len == 0))
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char		*ubuf, *rbuf;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = min (len, (unsigned) limit);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* else transfer packet(s) */
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ubuf = urb->transfer_buffer + urb->actual_length;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rbuf = req->req.buf + req->req.actual;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (to_host)
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (ubuf, rbuf, len);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (rbuf, ubuf, len);
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit -= len;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->actual_length += len;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.actual += len;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * need to emulate such data-in-flight.  so we only show part
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * of the URB_SHORT_NOT_OK effect: completion status.
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, -EOVERFLOW);
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb,
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						(urb->transfer_flags
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							& URB_SHORT_NOT_OK)
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						? -EREMOTEIO : 0);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						& URB_ZERO_PACKET)) {
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock (&dum->lock);
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.complete (&ep->ep, &req->req);
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock (&dum->lock);
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status != -EINPROGRESS)
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_active(dum)	((dum->port_status & \
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!is_active (dum))
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return &dum->ep [0];
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_timer (unsigned long _dum)
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum = (struct dummy *) _dum;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum), "bogus device speed\n");
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->udev) {
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum),
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&dum->lock, flags);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->ep [i].already_seen = 0;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) {
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status != -EINPROGRESS) {
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* likely it was just unlinked */
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1290391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		} else if (dum->rh_state != DUMMY_RH_RUNNING)
1291391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = usb_pipetype (urb->pipe);
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (usb_pipein (urb->pipe))
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_dbg (dummy_dev(dum),
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -EPROTO);
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && urb->error_count) {
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -EPIPE);
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && ep->setup_stage) {
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct dummy_ep			*ep2;
1336cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			unsigned			w_index;
1337cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			unsigned			w_value;
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
1340cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			w_index = le16_to_cpu(setup.wIndex);
1341cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			w_value = le16_to_cpu(setup.wValue);
1342cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			if (le16_to_cpu(setup.wLength) !=
1343cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					urb->transfer_buffer_length) {
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, -EOVERFLOW);
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto return_urb;
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_for_each_entry (req, &ep->queue, queue) {
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				list_del_init (&req->queue);
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
1352d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "stale req = %p\n",
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.complete (&ep->ep, &req->req);
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (setup.bRequest) {
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_SET_ADDRESS:
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType != Dev_Request)
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
1373cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern				dum->address = w_value;
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
1375d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "set_address = %d\n",
1376cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern						w_value);
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = 0;
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_SET_FEATURE:
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_Request) {
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
1382cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					switch (w_value) {
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					case USB_DEVICE_REMOTE_WAKEUP:
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
13855742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_B_HNP_ENABLE:
13865742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.b_hnp_enable = 1;
13875742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13885742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_A_HNP_SUPPORT:
13895742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.a_hnp_support = 1;
13905742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13915742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_A_ALT_HNP_SUPPORT:
13925742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.a_alt_hnp_support
13935742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							= 1;
13945742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					default:
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (value == 0) {
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						dum->devstatus |=
1400cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern							(1 << w_value);
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						maybe_set_status (urb, 0);
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else if (setup.bRequestType == Ep_Request) {
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint halt
1406cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					ep2 = find_endpoint (dum, w_index);
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (!ep2) {
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep2->halted = 1;
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_CLEAR_FEATURE:
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_Request) {
1418cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					switch (w_value) {
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					case USB_DEVICE_REMOTE_WAKEUP:
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						dum->devstatus &= ~(1 <<
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							USB_DEVICE_REMOTE_WAKEUP);
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = 0;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						maybe_set_status (urb, 0);
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					default:
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else if (setup.bRequestType == Ep_Request) {
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint halt
1431cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					ep2 = find_endpoint (dum, w_index);
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (!ep2) {
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep2->halted = 0;
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_GET_STATUS:
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_InRequest
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						|| setup.bRequestType
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							== Intf_InRequest
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						|| setup.bRequestType
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							== Ep_InRequest
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						) {
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					char *buf;
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// device: remote wakeup, selfpowered
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// interface: nothing
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint: halt
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf = (char *)urb->transfer_buffer;
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (urb->transfer_buffer_length > 0) {
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (setup.bRequestType ==
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								Ep_InRequest) {
1457cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern	ep2 = find_endpoint (dum, w_index);
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep2) {
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value = -EOPNOTSUPP;
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf [0] = ep2->halted;
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						} else if (setup.bRequestType ==
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								Dev_InRequest) {
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							buf [0] = (u8)
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								dum->devstatus;
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						} else
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							buf [0] = 0;
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (urb->transfer_buffer_length > 1)
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						buf [1] = 0;
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					urb->actual_length = min (2,
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						urb->transfer_buffer_length);
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = dum->driver->setup (&dum->gadget,
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
1499d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern					dev_dbg (udc_dev(dum),
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, -EPIPE);
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (usb_pipetype (urb->pipe)) {
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -ENOSYS);
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// case PIPE_BULK:  case PIPE_CONTROL:
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		treat_control_like_bulk:
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			total = transfer (dum, urb, ep, limit);
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status == -EINPROGRESS)
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->hcpriv = NULL;
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del (&urbp->urbp_list);
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (urbp);
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL);
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1555391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (list_empty (&dum->urbp_list)) {
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_put_dev (dum->udev);
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->udev = NULL;
1558391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	} else if (dum->rh_state == DUMMY_RH_RUNNING) {
1559391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1560391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1569c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1570c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1571c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1572c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1573c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf)
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1579391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
1584391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (hcd->state != HC_STATE_RUNNING)
1585391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1586f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1587f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
1588f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1589f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status &= ~USB_PORT_STAT_SUSPEND;
1590f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		set_link_state (dum);
1591f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1592f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1593391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & PORT_C_MASK) != 0) {
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
1596391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern				dum->port_status);
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1598391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		if (dum->rh_state == DUMMY_RH_SUSPENDED)
1599391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			usb_hcd_resume_root_hub (hcd);
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1601391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc)
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (desc, 0, sizeof *desc);
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1612cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern	desc->wHubCharacteristics = (__force __u16)
1613cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			(__constant_cpu_to_le16 (0x0001));
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bitmap [0] = 0xff;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bitmap [1] = 0xff;
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control (
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (hcd->state != HC_STATE_RUNNING)
1632391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1633391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
1642c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			if (dum->port_status & USB_PORT_STAT_SUSPEND) {
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->resuming = 1;
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->re_timeout = jiffies +
1646f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
1650f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->port_status & USB_PORT_STAT_POWER)
1651f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				dev_dbg (dummy_dev(dum), "power-off\n");
1652f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dum->port_status &= ~(1 << wValue);
1655f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			set_link_state (dum);
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hub_descriptor ((struct usb_hub_descriptor *) buf);
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
1662cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		*(__le32 *) buf = __constant_cpu_to_le32 (0);
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1671f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if (dum->resuming &&
1672f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				time_after_eq (jiffies, dum->re_timeout)) {
1673c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1674c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1676f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
1677f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				time_after_eq (jiffies, dum->re_timeout)) {
1678c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
1679c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status &= ~USB_PORT_STAT_RESET;
1680f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->pullup) {
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->port_status |= USB_PORT_STAT_ENABLE;
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* give it the best speed we agree on */
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->gadget.speed = dum->driver->speed;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->gadget.ep0->maxpacket = 64;
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				switch (dum->gadget.speed) {
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case USB_SPEED_HIGH:
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->port_status |=
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						USB_PORT_STAT_HIGH_SPEED;
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case USB_SPEED_LOW:
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->gadget.ep0->maxpacket = 8;
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->port_status |=
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						USB_PORT_STAT_LOW_SPEED;
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				default:
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->gadget.speed = USB_SPEED_FULL;
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1701f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		set_link_state (dum);
1702cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
1703cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
1711f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->active) {
1712c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern				dum->port_status |= USB_PORT_STAT_SUSPEND;
1713f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1714f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
1715f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
1716f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
1717f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				set_link_state (dum);
1718f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
1719f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						& dum->devstatus) != 0)
1720f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					dev_dbg (dummy_dev(dum),
17215742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1724f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
1725f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status |= USB_PORT_STAT_POWER;
1726f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			set_link_state (dum);
1727f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
1729f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
1730f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status &= ~(USB_PORT_STAT_ENABLE
1731f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
1732f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
1733391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			dum->devstatus = 0;
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* 50msec reset signaling */
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dum->re_timeout = jiffies + msecs_to_jiffies(50);
1736f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1738f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
1739f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				dum->port_status |= (1 << wValue);
1740f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				set_link_state (dum);
1741f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			}
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg (dummy_dev(dum),
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
1754685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
1755685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	if ((dum->port_status & PORT_C_MASK) != 0)
1756685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern		usb_hcd_poll_rh_status (hcd);
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1760391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternstatic int dummy_hub_suspend (struct usb_hcd *hcd)
1761391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1762391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy *dum = hcd_to_dummy (hcd);
1763391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1764391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
1765391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->rh_state = DUMMY_RH_SUSPENDED;
1766391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
1767391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
1768391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1769391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1770391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1771391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternstatic int dummy_hub_resume (struct usb_hcd *hcd)
1772391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1773391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy *dum = hcd_to_dummy (hcd);
1774391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1775391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
1776391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->rh_state = DUMMY_RH_RUNNING;
1777391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
1778391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (!list_empty(&dum->urbp_list))
1779391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		mod_timer (&dum->timer, jiffies);
1780391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
1781391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1782391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb)
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ep = usb_pipeendpoint (urb->pipe);
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf (buf, size,
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (urb->dev->speed) {
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_LOW:	s = "ls"; break;
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_FULL:	s = "fs"; break;
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_HIGH:	s = "hs"; break;
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 default:		s = "?"; break;
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (usb_pipetype (urb->pipe)) { \
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_CONTROL:	s = ""; break; \
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_BULK:	s = "-bulk"; break; \
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_INTERRUPT:	s = "-int"; break; \
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 default: 		s = "-iso"; break; \
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}; s;}),
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
181310523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf)
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd = dev_get_drvdata (dev);
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum = hcd_to_dummy (hcd);
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_start (struct usb_hcd *hcd)
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init (&dum->lock);
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer (&dum->timer);
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->timer.function = dummy_timer;
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->timer.data = (unsigned long) dum;
1850391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->rh_state = DUMMY_RH_RUNNING;
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&dum->urbp_list);
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1854bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern	/* only show a low-power port: just 8mA */
1855bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern	hcd->power_budget = 8;
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
1857685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18595742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
18605742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
18615742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
18625742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file (dummy_dev(dum), &dev_attr_urbs);
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd)
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_gadget_unregister_driver (dum->driver);
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_info (dummy_dev(dum), "stopped\n");
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd)
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_g_get_frame (NULL);
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct hc_driver dummy_hcd = {
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hcd_priv_size =	sizeof(struct dummy),
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flags =		HCD_USB2,
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_enqueue = 		dummy_urb_enqueue,
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_dequeue = 		dummy_urb_dequeue,
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame_number = 	dummy_h_get_frame,
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_status_data = 	dummy_hub_status,
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_control = 		dummy_hub_control,
1903391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.hub_suspend =		dummy_hub_suspend,
1904391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.hub_resume =		dummy_hub_resume,
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1907d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic int dummy_hcd_probe (struct device *dev)
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd;
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd = usb_create_hcd (&dummy_hcd, dev, dev->bus_id);
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!hcd)
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	the_controller = hcd_to_dummy (hcd);
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_add_hcd(hcd, 0, 0);
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_put_hcd (hcd);
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		the_controller = NULL;
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1927d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic int dummy_hcd_remove (struct device *dev)
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd;
19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd = dev_get_drvdata (dev);
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_remove_hcd (hcd);
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_put_hcd (hcd);
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	the_controller = NULL;
1935d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1938391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternstatic int dummy_hcd_suspend (struct device *dev, pm_message_t state,
1939391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		u32 level)
1940391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1941391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
1942391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1943391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (level != SUSPEND_DISABLE)
1944391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return 0;
1945391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1946391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev_dbg (dev, "%s\n", __FUNCTION__);
1947391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	hcd = dev_get_drvdata (dev);
1948391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1949391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#ifndef CONFIG_USB_SUSPEND
1950391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* Otherwise this would never happen */
1951391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_lock_device (hcd->self.root_hub);
1952391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dummy_hub_suspend (hcd);
1953391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_unlock_device (hcd->self.root_hub);
1954391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#endif
1955391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1956391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	hcd->state = HC_STATE_SUSPENDED;
1957391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1958391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1959391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1960391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternstatic int dummy_hcd_resume (struct device *dev, u32 level)
1961391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1962391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
1963391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1964391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (level != RESUME_ENABLE)
1965391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return 0;
1966391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1967391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev_dbg (dev, "%s\n", __FUNCTION__);
1968391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	hcd = dev_get_drvdata (dev);
1969391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	hcd->state = HC_STATE_RUNNING;
1970391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1971391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#ifndef CONFIG_USB_SUSPEND
1972391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* Otherwise this would never happen */
1973391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_lock_device (hcd->self.root_hub);
1974391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dummy_hub_resume (hcd);
1975391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_unlock_device (hcd->self.root_hub);
1976391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#endif
1977391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1978391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (hcd);
1979391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1980391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1981391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1982d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct device_driver dummy_hcd_driver = {
1983d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) driver_name,
1984d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.bus		= &platform_bus_type,
1985d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
1986d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
1987391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
1988391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
1989d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1993d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* These don't need to do anything because the pdev structures are
1994d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * statically allocated. */
1995d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
1996d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_udc_release (struct device *dev) {}
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1998d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
1999d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_hcd_release (struct device *dev) {}
2000d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2001d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct platform_device		the_udc_pdev = {
2002d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) gadget_name,
2003d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.id		= -1,
2004d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.dev		= {
2005d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		.release	= dummy_udc_release,
2006d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	},
2007d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct platform_device		the_hcd_pdev = {
2010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) driver_name,
2011d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.id		= -1,
2012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.dev		= {
2013d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		.release	= dummy_hcd_release,
2014d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	},
2015d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void)
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	retval;
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_disabled ())
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2023d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2024d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = driver_register (&dummy_hcd_driver);
2025d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
2027d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2028d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = driver_register (&dummy_udc_driver);
2029d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2030d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2031d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2032d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = platform_device_register (&the_hcd_pdev);
2033d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2034d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_hcd;
2035d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2036d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = platform_device_register (&the_udc_pdev);
2037d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2038d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc;
2039d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2040d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2041d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc:
2042d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_hcd_pdev);
2043d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_hcd:
2044d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	driver_unregister (&dummy_udc_driver);
2045d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
2046d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	driver_unregister (&dummy_hcd_driver);
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init);
20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void)
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2053d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_udc_pdev);
2054d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_hcd_pdev);
2055d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	driver_unregister (&dummy_udc_driver);
2056d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	driver_unregister (&dummy_hcd_driver);
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup);
2059