dummy_hcd.c revision d052d1beff706920e82c5d55006b08e256b5df09
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>
53d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
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 *
47355016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t 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,
51055016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t 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
5435db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req,
54455016f10e31bb15b85d8c500f979dfdceb37d548Al Viro		gfp_t mem_flags)
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_req || !list_empty (&req->queue) || !_req->complete)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !is_enabled (dum))
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
564d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&dum->fifo_req.queue) &&
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&ep->queue) &&
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy (dum->fifo_buf, _req->buf, _req->length);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail (&req->queue, &ep->queue);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
627d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		dev_dbg (udc_dev(dum),
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_set_halt (struct usb_ep *_ep, int value)
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 0;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!list_empty (&ep->queue))
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_buffer	= dummy_alloc_buffer,
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_buffer	= dummy_free_buffer,
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* map, unmap, ... eventually hook the "generic" dma calls */
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget)
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday (&tv);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget)
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = gadget_to_dummy (_gadget);
691391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE)
6925742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
694391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
695391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
696391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
697391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			 dum->rh_state != DUMMY_RH_SUSPENDED)
698391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
699391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
700391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->resuming = 1;
704f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->re_timeout = jiffies + msecs_to_jiffies(20);
705685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = gadget_to_dummy (_gadget);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value)
722f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
723f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
724f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
725f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
726f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum = gadget_to_dummy (_gadget);
727f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
728f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
729f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
730f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
731685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
732685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
733f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
734f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
735f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
740f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
74710523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf)
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = gadget_dev_to_dummy (dev);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
755cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_register_driver (struct usb_gadget_driver *driver)
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = the_controller;
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval, i;
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum)
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->driver)
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!driver->bind || !driver->unbind || !driver->setup
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| driver->speed == USB_SPEED_UNKNOWN)
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7915742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&dum->gadget.ep_list);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.name = ep_name [i];
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.ops = &dummy_ep_ops;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list);
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = ep->already_seen = ep->setup_stage = 0;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.maxpacket = ~0;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->last_io = jiffies;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->gadget = &dum->gadget;
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->desc = NULL;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		INIT_LIST_HEAD (&ep->queue);
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->gadget.ep0 = &dum->ep [0].ep;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->ep [0].ep.maxpacket = 64;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del_init (&dum->ep [0].ep.ep_list);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&dum->fifo_req.queue);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->gadget.dev.driver = &driver->driver;
818d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((retval = driver->bind (&dum->gadget)) != 0) {
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->driver = NULL;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->gadget.dev.driver = NULL;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->driver.bus = dum->gadget.dev.parent->bus;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_register (&driver->driver);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_bind_driver (&dum->gadget.dev);
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* khubd will enumerate this in a while */
831f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irq (&dum->lock);
832f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 1;
833f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
834f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irq (&dum->lock);
835685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
836685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_register_driver);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_unregister_driver (struct usb_gadget_driver *driver)
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = the_controller;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum)
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!driver || driver != dum->driver)
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
852d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
856f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 0;
857f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->unbind (&dum->gadget);
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_release_driver (&dum->gadget.dev);
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_unregister (&driver->driver);
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
866f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
867f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 0;
868f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
869f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
870f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
871685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_unregister_driver);
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
878cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern/* just declare this in any driver that really need it */
879cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternextern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
880cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOSYS;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (net2280_set_fifo_mode);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
887d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
888d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
889d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
890d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
891d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev)
892d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
893d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern#if 0		/* usb_bus_put isn't EXPORTed! */
894d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	struct dummy	*dum = gadget_dev_to_dummy (dev);
895d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
896d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	usb_bus_put (&dummy_to_hcd (dum)->self);
897d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern#endif
898d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
899d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
900d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic int dummy_udc_probe (struct device *dev)
901d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
902d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	struct dummy	*dum = the_controller;
903d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
904d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
905d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
906d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
907d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.is_dualspeed = 1;
908d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
909d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	/* maybe claim OTG support, though we won't complete HNP */
910d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
911d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
912d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	strcpy (dum->gadget.dev.bus_id, "gadget");
913d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.parent = dev;
914d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
915d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	rc = device_register (&dum->gadget.dev);
916d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (rc < 0)
917d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
918d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
919d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern#if 0		/* usb_bus_get isn't EXPORTed! */
920d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	usb_bus_get (&dummy_to_hcd (dum)->self);
921d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern#endif
922d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
923d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_set_drvdata (dev, dum);
924d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_create_file (&dum->gadget.dev, &dev_attr_function);
925d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
926d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
927d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
928d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic int dummy_udc_remove (struct device *dev)
929d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
930d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	struct dummy	*dum = dev_get_drvdata (dev);
931d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
932d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_set_drvdata (dev, NULL);
933d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_remove_file (&dum->gadget.dev, &dev_attr_function);
934d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_unregister (&dum->gadget.dev);
935d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
936d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
937d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9389480e307cd88ef09ec9294c7d97ebec18e6d2221Russell Kingstatic int dummy_udc_suspend (struct device *dev, pm_message_t state)
939391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
940391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy	*dum = dev_get_drvdata(dev);
941391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
942391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev_dbg (dev, "%s\n", __FUNCTION__);
943391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
944391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->udc_suspended = 1;
945391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
946391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
947391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
948391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev->power.power_state = state;
949391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
950391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
951391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
952391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
9539480e307cd88ef09ec9294c7d97ebec18e6d2221Russell Kingstatic int dummy_udc_resume (struct device *dev)
954391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
955391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy	*dum = dev_get_drvdata(dev);
956391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
957391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev_dbg (dev, "%s\n", __FUNCTION__);
958391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
959391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->udc_suspended = 0;
960391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
961391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
962391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
963391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev->power.power_state = PMSG_ON;
964391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
965391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
966391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
967391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
968d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct device_driver dummy_udc_driver = {
969d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) gadget_name,
970d0d5049fb02fc1082c17e08deecd6fed8db549b6Ben Dooks	.owner		= THIS_MODULE,
971d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.bus		= &platform_bus_type,
972d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
973d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
974391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
975391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
976d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue (
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_host_endpoint	*ep,
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
99655016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t				mem_flags
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urb->transfer_buffer && urb->transfer_buffer_length)
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp = kmalloc (sizeof *urbp, mem_flags);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->udev) {
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->udev = urb->dev;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_get_dev (dum->udev);
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (unlikely (dum->udev != urb->dev))
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum), "usb_device address has changed!\n");
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail (&urbp->urbp_list, &dum->urbp_list);
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!timer_pending (&dum->timer))
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mod_timer (&dum->timer, jiffies + 1);
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1034391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy	*dum;
1035391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1036391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1037391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1038391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1039391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum = hcd_to_dummy (hcd);
1040391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irqsave (&dum->lock, flags);
1041391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
1042391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		mod_timer (&dum->timer, jiffies);
1043391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irqrestore (&dum->lock, flags);
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void maybe_set_status (struct urb *urb, int status)
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock (&urb->lock);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (urb->status == -EINPROGRESS)
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->status = status;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock (&urb->lock);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstransfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min (host_len, dev_len);
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_host = usb_pipein (urb->pipe);
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely (len == 0))
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char		*ubuf, *rbuf;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = min (len, (unsigned) limit);
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* else transfer packet(s) */
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ubuf = urb->transfer_buffer + urb->actual_length;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rbuf = req->req.buf + req->req.actual;
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (to_host)
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (ubuf, rbuf, len);
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (rbuf, ubuf, len);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit -= len;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->actual_length += len;
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.actual += len;
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * need to emulate such data-in-flight.  so we only show part
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * of the URB_SHORT_NOT_OK effect: completion status.
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, -EOVERFLOW);
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb,
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						(urb->transfer_flags
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							& URB_SHORT_NOT_OK)
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						? -EREMOTEIO : 0);
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						& URB_ZERO_PACKET)) {
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock (&dum->lock);
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.complete (&ep->ep, &req->req);
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock (&dum->lock);
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status != -EINPROGRESS)
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_active(dum)	((dum->port_status & \
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!is_active (dum))
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return &dum->ep [0];
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_timer (unsigned long _dum)
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum = (struct dummy *) _dum;
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum), "bogus device speed\n");
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->udev) {
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum),
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&dum->lock, flags);
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->ep [i].already_seen = 0;
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) {
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status != -EINPROGRESS) {
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* likely it was just unlinked */
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1285391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		} else if (dum->rh_state != DUMMY_RH_RUNNING)
1286391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = usb_pipetype (urb->pipe);
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (usb_pipein (urb->pipe))
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_dbg (dummy_dev(dum),
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -EPROTO);
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && urb->error_count) {
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -EPIPE);
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && ep->setup_stage) {
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct dummy_ep			*ep2;
1331cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			unsigned			w_index;
1332cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			unsigned			w_value;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
1335cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			w_index = le16_to_cpu(setup.wIndex);
1336cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			w_value = le16_to_cpu(setup.wValue);
1337cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			if (le16_to_cpu(setup.wLength) !=
1338cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					urb->transfer_buffer_length) {
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, -EOVERFLOW);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto return_urb;
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_for_each_entry (req, &ep->queue, queue) {
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				list_del_init (&req->queue);
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
1347d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "stale req = %p\n",
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.complete (&ep->ep, &req->req);
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (setup.bRequest) {
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_SET_ADDRESS:
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType != Dev_Request)
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
1368cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern				dum->address = w_value;
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
1370d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "set_address = %d\n",
1371cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern						w_value);
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = 0;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_SET_FEATURE:
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_Request) {
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
1377cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					switch (w_value) {
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					case USB_DEVICE_REMOTE_WAKEUP:
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
13805742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_B_HNP_ENABLE:
13815742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.b_hnp_enable = 1;
13825742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13835742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_A_HNP_SUPPORT:
13845742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.a_hnp_support = 1;
13855742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13865742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_A_ALT_HNP_SUPPORT:
13875742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.a_alt_hnp_support
13885742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							= 1;
13895742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					default:
13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (value == 0) {
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						dum->devstatus |=
1395cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern							(1 << w_value);
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						maybe_set_status (urb, 0);
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else if (setup.bRequestType == Ep_Request) {
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint halt
1401cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					ep2 = find_endpoint (dum, w_index);
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (!ep2) {
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep2->halted = 1;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_CLEAR_FEATURE:
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_Request) {
1413cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					switch (w_value) {
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					case USB_DEVICE_REMOTE_WAKEUP:
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						dum->devstatus &= ~(1 <<
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							USB_DEVICE_REMOTE_WAKEUP);
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = 0;
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						maybe_set_status (urb, 0);
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					default:
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else if (setup.bRequestType == Ep_Request) {
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint halt
1426cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					ep2 = find_endpoint (dum, w_index);
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (!ep2) {
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep2->halted = 0;
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_GET_STATUS:
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_InRequest
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						|| setup.bRequestType
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							== Intf_InRequest
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						|| setup.bRequestType
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							== Ep_InRequest
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						) {
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					char *buf;
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// device: remote wakeup, selfpowered
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// interface: nothing
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint: halt
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf = (char *)urb->transfer_buffer;
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (urb->transfer_buffer_length > 0) {
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (setup.bRequestType ==
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								Ep_InRequest) {
1452cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern	ep2 = find_endpoint (dum, w_index);
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep2) {
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value = -EOPNOTSUPP;
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf [0] = ep2->halted;
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						} else if (setup.bRequestType ==
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								Dev_InRequest) {
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							buf [0] = (u8)
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								dum->devstatus;
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						} else
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							buf [0] = 0;
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (urb->transfer_buffer_length > 1)
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						buf [1] = 0;
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					urb->actual_length = min (2,
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						urb->transfer_buffer_length);
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = dum->driver->setup (&dum->gadget,
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
1494d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern					dev_dbg (udc_dev(dum),
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, -EPIPE);
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (usb_pipetype (urb->pipe)) {
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -ENOSYS);
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// case PIPE_BULK:  case PIPE_CONTROL:
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		treat_control_like_bulk:
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			total = transfer (dum, urb, ep, limit);
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status == -EINPROGRESS)
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->hcpriv = NULL;
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del (&urbp->urbp_list);
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (urbp);
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL);
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1550391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (list_empty (&dum->urbp_list)) {
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_put_dev (dum->udev);
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->udev = NULL;
1553391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	} else if (dum->rh_state == DUMMY_RH_RUNNING) {
1554391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1555391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1564c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1565c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1566c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1567c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1568c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf)
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1574391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
1579391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (hcd->state != HC_STATE_RUNNING)
1580391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1581f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1582f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
1583f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1584f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status &= ~USB_PORT_STAT_SUSPEND;
1585f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		set_link_state (dum);
1586f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1587f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1588391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & PORT_C_MASK) != 0) {
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
1591391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern				dum->port_status);
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1593391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		if (dum->rh_state == DUMMY_RH_SUSPENDED)
1594391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			usb_hcd_resume_root_hub (hcd);
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1596391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc)
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (desc, 0, sizeof *desc);
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1607cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern	desc->wHubCharacteristics = (__force __u16)
1608cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			(__constant_cpu_to_le16 (0x0001));
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bitmap [0] = 0xff;
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bitmap [1] = 0xff;
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control (
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1626391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (hcd->state != HC_STATE_RUNNING)
1627391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1628391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
1637c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			if (dum->port_status & USB_PORT_STAT_SUSPEND) {
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->resuming = 1;
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->re_timeout = jiffies +
1641f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
1645f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->port_status & USB_PORT_STAT_POWER)
1646f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				dev_dbg (dummy_dev(dum), "power-off\n");
1647f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dum->port_status &= ~(1 << wValue);
1650f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			set_link_state (dum);
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hub_descriptor ((struct usb_hub_descriptor *) buf);
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
1657cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		*(__le32 *) buf = __constant_cpu_to_le32 (0);
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1666f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if (dum->resuming &&
1667f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				time_after_eq (jiffies, dum->re_timeout)) {
1668c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1669c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1671f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
1672f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				time_after_eq (jiffies, dum->re_timeout)) {
1673c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
1674c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status &= ~USB_PORT_STAT_RESET;
1675f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->pullup) {
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->port_status |= USB_PORT_STAT_ENABLE;
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* give it the best speed we agree on */
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->gadget.speed = dum->driver->speed;
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->gadget.ep0->maxpacket = 64;
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				switch (dum->gadget.speed) {
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case USB_SPEED_HIGH:
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->port_status |=
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						USB_PORT_STAT_HIGH_SPEED;
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case USB_SPEED_LOW:
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->gadget.ep0->maxpacket = 8;
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->port_status |=
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						USB_PORT_STAT_LOW_SPEED;
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				default:
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->gadget.speed = USB_SPEED_FULL;
16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1696f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		set_link_state (dum);
1697cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
1698cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
1706f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->active) {
1707c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern				dum->port_status |= USB_PORT_STAT_SUSPEND;
1708f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1709f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
1710f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
1711f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
1712f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				set_link_state (dum);
1713f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
1714f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						& dum->devstatus) != 0)
1715f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					dev_dbg (dummy_dev(dum),
17165742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1719f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
1720f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status |= USB_PORT_STAT_POWER;
1721f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			set_link_state (dum);
1722f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
1724f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
1725f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status &= ~(USB_PORT_STAT_ENABLE
1726f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
1727f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
1728391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			dum->devstatus = 0;
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* 50msec reset signaling */
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dum->re_timeout = jiffies + msecs_to_jiffies(50);
1731f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1733f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
1734f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				dum->port_status |= (1 << wValue);
1735f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				set_link_state (dum);
1736f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			}
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg (dummy_dev(dum),
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
1749685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
1750685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	if ((dum->port_status & PORT_C_MASK) != 0)
1751685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern		usb_hcd_poll_rh_status (hcd);
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17550c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd)
1756391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1757391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy *dum = hcd_to_dummy (hcd);
1758391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1759391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
1760391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->rh_state = DUMMY_RH_SUSPENDED;
1761391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
1762391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
1763391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1764391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1765391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
17660c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd)
1767391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1768391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy *dum = hcd_to_dummy (hcd);
1769391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1770391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
1771391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->rh_state = DUMMY_RH_RUNNING;
1772391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
1773391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (!list_empty(&dum->urbp_list))
1774391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		mod_timer (&dum->timer, jiffies);
1775391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
1776391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1777391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb)
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ep = usb_pipeendpoint (urb->pipe);
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf (buf, size,
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (urb->dev->speed) {
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_LOW:	s = "ls"; break;
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_FULL:	s = "fs"; break;
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_HIGH:	s = "hs"; break;
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 default:		s = "?"; break;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (usb_pipetype (urb->pipe)) { \
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_CONTROL:	s = ""; break; \
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_BULK:	s = "-bulk"; break; \
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_INTERRUPT:	s = "-int"; break; \
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 default: 		s = "-iso"; break; \
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}; s;}),
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
180810523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf)
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd = dev_get_drvdata (dev);
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum = hcd_to_dummy (hcd);
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_start (struct usb_hcd *hcd)
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init (&dum->lock);
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer (&dum->timer);
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->timer.function = dummy_timer;
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->timer.data = (unsigned long) dum;
1845391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->rh_state = DUMMY_RH_RUNNING;
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&dum->urbp_list);
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1849bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern	/* only show a low-power port: just 8mA */
1850bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern	hcd->power_budget = 8;
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
1852685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18545742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
18555742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
18565742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
18575742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_create_file (dummy_dev(dum), &dev_attr_urbs);
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd)
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_gadget_unregister_driver (dum->driver);
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_info (dummy_dev(dum), "stopped\n");
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd)
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_g_get_frame (NULL);
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct hc_driver dummy_hcd = {
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hcd_priv_size =	sizeof(struct dummy),
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flags =		HCD_USB2,
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_enqueue = 		dummy_urb_enqueue,
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_dequeue = 		dummy_urb_dequeue,
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame_number = 	dummy_h_get_frame,
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_status_data = 	dummy_hub_status,
18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_control = 		dummy_hub_control,
18980c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_suspend =		dummy_bus_suspend,
18990c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_resume =		dummy_bus_resume,
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1902d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic int dummy_hcd_probe (struct device *dev)
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd;
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd = usb_create_hcd (&dummy_hcd, dev, dev->bus_id);
19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!hcd)
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	the_controller = hcd_to_dummy (hcd);
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_add_hcd(hcd, 0, 0);
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_put_hcd (hcd);
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		the_controller = NULL;
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1922d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic int dummy_hcd_remove (struct device *dev)
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd;
19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd = dev_get_drvdata (dev);
19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_remove_hcd (hcd);
19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_put_hcd (hcd);
19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	the_controller = NULL;
1930d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19339480e307cd88ef09ec9294c7d97ebec18e6d2221Russell Kingstatic int dummy_hcd_suspend (struct device *dev, pm_message_t state)
1934391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1935391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
1936391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1937391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev_dbg (dev, "%s\n", __FUNCTION__);
1938391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	hcd = dev_get_drvdata (dev);
1939391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1940391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	hcd->state = HC_STATE_SUSPENDED;
1941391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1942391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1943391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
19449480e307cd88ef09ec9294c7d97ebec18e6d2221Russell Kingstatic int dummy_hcd_resume (struct device *dev)
1945391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1946391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
1947391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1948391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dev_dbg (dev, "%s\n", __FUNCTION__);
1949391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	hcd = dev_get_drvdata (dev);
1950391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	hcd->state = HC_STATE_RUNNING;
1951391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1952391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (hcd);
1953391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1954391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1955391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1956d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct device_driver dummy_hcd_driver = {
1957d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) driver_name,
1958d0d5049fb02fc1082c17e08deecd6fed8db549b6Ben Dooks	.owner		= THIS_MODULE,
1959d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.bus		= &platform_bus_type,
1960d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
1961d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
1962391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
1963391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
1964d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1966d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1968d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* These don't need to do anything because the pdev structures are
1969d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * statically allocated. */
1970d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
1971d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_udc_release (struct device *dev) {}
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1973d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
1974d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_hcd_release (struct device *dev) {}
1975d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1976d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct platform_device		the_udc_pdev = {
1977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) gadget_name,
1978d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.id		= -1,
1979d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.dev		= {
1980d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		.release	= dummy_udc_release,
1981d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	},
1982d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1984d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct platform_device		the_hcd_pdev = {
1985d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) driver_name,
1986d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.id		= -1,
1987d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.dev		= {
1988d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		.release	= dummy_hcd_release,
1989d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	},
1990d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void)
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	retval;
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_disabled ())
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1998d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1999d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = driver_register (&dummy_hcd_driver);
2000d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
2002d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2003d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = driver_register (&dummy_udc_driver);
2004d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2005d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2006d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2007d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = platform_device_register (&the_hcd_pdev);
2008d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_hcd;
2010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2011d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = platform_device_register (&the_udc_pdev);
2012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2013d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc;
2014d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2015d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2016d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc:
2017d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_hcd_pdev);
2018d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_hcd:
2019d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	driver_unregister (&dummy_udc_driver);
2020d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
2021d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	driver_unregister (&dummy_hcd_driver);
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init);
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void)
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2028d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_udc_pdev);
2029d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_hcd_pdev);
2030d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	driver_unregister (&dummy_udc_driver);
2031d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	driver_unregister (&dummy_hcd_driver);
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup);
2034