dummy_hcd.c revision b0d9efba3ec53468984aecef8eeaf079089f2e5a
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#include <linux/module.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
47d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb_gadget.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "../core/hcd.h"
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC	"USB Host+Gadget Emulator"
62391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern#define DRIVER_VERSION	"02 May 2005"
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_name [] = "dummy_hcd";
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	driver_desc [] = "USB Host+Gadget Emulator";
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char	gadget_name [] = "dummy_udc";
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION (DRIVER_DESC);
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("David Brownell");
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE ("GPL");
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* gadget side driver data structres */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_ep {
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			last_io;	/* jiffies timestamp */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		*gadget;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usb_endpoint_descriptor *desc;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_ep			ep;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			halted : 1;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			already_seen : 1;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			setup_stage : 1;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy_request {
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		queue;		/* ep's requests */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_request		req;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_ep, struct dummy_ep, ep);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy_request *usb_request_to_dummy_request
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(struct usb_request *_req)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (_req, struct dummy_request, req);
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Every device has ep0 for control requests, plus up to 30 more endpoints,
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in one of two types:
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Configurable:  direction (in/out), type (bulk, iso, etc), and endpoint
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     number can be changed.  Names like "ep-a" are used for this type.
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - Fixed Function:  in other cases.  some characteristics may be mutable;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     that'd be hardware-specific.  Names like "ep12out-bulk" are used.
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gadget drivers are responsible for not setting up conflicting endpoint
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations, illegal or unsupported packet lengths, and so on.
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char ep0name [] = "ep0";
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *const ep_name [] = {
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep0name,				/* everyone has ep0 */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* act like a net2280: high speed, six configurable endpoints */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like pxa250: fifteen fixed function endpoints */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ep15in-int",
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* or like sa1100: two fixed function endpoints */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"ep1out-bulk", "ep2in-bulk",
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
13652950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser#define DUMMY_ENDPOINTS	ARRAY_SIZE(ep_name)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
138d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
139d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIFO_SIZE		64
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct urbp {
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb		*urb;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head	urbp_list;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
147391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
148391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sternenum dummy_rh_state {
149391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RESET,
150391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_SUSPENDED,
151391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	DUMMY_RH_RUNNING
152391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern};
153391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dummy {
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t			lock;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE/GADGET side support
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep			ep [DUMMY_ENDPOINTS];
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int				address;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget		gadget;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_gadget_driver	*driver;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request		fifo_req;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8				fifo_buf [FIFO_SIZE];
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16				devstatus;
167391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned			udc_suspended:1;
168f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			pullup:1;
169f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			active:1;
170f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned			old_active:1;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER/HOST side support
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
175391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	enum dummy_rh_state		rh_state;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timer_list		timer;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32				port_status;
178f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	u32				old_status;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned			resuming:1;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long			re_timeout;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_device		*udev;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head		urbp_list;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (struct dummy *) (hcd->hcd_priv);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct usb_hcd *dummy_to_hcd (struct dummy *dum)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of((void *) dum, struct usb_hcd, hcd_priv);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct device *dummy_dev (struct dummy *dum)
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_to_hcd(dum)->self.controller;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic inline struct device *udc_dev (struct dummy *dum)
202d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
203d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return dum->gadget.dev.parent;
204d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
205d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (ep->gadget, struct dummy, gadget);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget)
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (gadget, struct dummy, gadget);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct dummy *gadget_dev_to_dummy (struct device *dev)
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return container_of (dev, struct dummy, gadget.dev);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy			*the_controller;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
225f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* SLAVE/GADGET SIDE UTILITY ROUTINES */
226f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
227f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* called with spinlock held */
228f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void nuke (struct dummy *dum, struct dummy_ep *ep)
229f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
230f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	while (!list_empty (&ep->queue)) {
231f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		struct dummy_request	*req;
232f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
233f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req = list_entry (ep->queue.next, struct dummy_request, queue);
234f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		list_del_init (&req->queue);
235f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.status = -ESHUTDOWN;
236f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
237f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_unlock (&dum->lock);
238f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		req->req.complete (&ep->ep, &req->req);
239f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		spin_lock (&dum->lock);
240f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
241f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
242f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
243f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
244f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
245f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstop_activity (struct dummy *dum)
246f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
247f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy_ep	*ep;
248f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
249f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* prevent any more requests */
250f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->address = 0;
251f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
252f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* The timer is left running so that outstanding URBs can fail */
253f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
254f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* nuke any pending requests first, so driver i/o is quiesced */
255f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
256f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		nuke (dum, ep);
257f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
258f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	/* driver now does any non-usb quiescing necessary */
259f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
260f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
261f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/* caller must hold lock */
262f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic void
263f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternset_link_state (struct dummy *dum)
264f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
265f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->active = 0;
266f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
267f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status = 0;
268391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
269391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* UDC suspend must cause a disconnect */
270391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	else if (!dum->pullup || dum->udc_suspended) {
271f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
272f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					USB_PORT_STAT_ENABLE |
273f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					USB_PORT_STAT_LOW_SPEED |
274f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					USB_PORT_STAT_HIGH_SPEED |
275f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					USB_PORT_STAT_SUSPEND);
276f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
277f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
278f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	} else {
279f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status |= USB_PORT_STAT_CONNECTION;
280f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
281f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
282f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
283f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
284391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
285391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern				dum->rh_state != DUMMY_RH_SUSPENDED)
286f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->active = 1;
287f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
288f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
289f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
290f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->resuming = 0;
291f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
292f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
293f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
294f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
295f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
296f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				dum->driver) {
297f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			stop_activity (dum);
298f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_unlock (&dum->lock);
299f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->driver->disconnect (&dum->gadget);
300f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_lock (&dum->lock);
301f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
302f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	} else if (dum->active != dum->old_active) {
303f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if (dum->old_active && dum->driver->suspend) {
304f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_unlock (&dum->lock);
305f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->driver->suspend (&dum->gadget);
306f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_lock (&dum->lock);
307f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		} else if (!dum->old_active && dum->driver->resume) {
308f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_unlock (&dum->lock);
309f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->driver->resume (&dum->gadget);
310f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			spin_lock (&dum->lock);
311f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		}
312f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
313f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
314f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->old_status = dum->port_status;
315f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->old_active = dum->active;
316f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
317f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
318f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern/*-------------------------------------------------------------------------*/
319f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SLAVE/GADGET SIDE DRIVER
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This only tracks gadget state.  All the work is done when the host
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * side tries some (emulated) i/o operation.  Real device controller
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers would do real i/o using dma, fifos, irqs, timers, etc.
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_enabled(dum) \
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(dum->port_status & USB_PORT_STAT_ENABLE)
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		max;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !desc || ep->desc || _ep->name == ep0name
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| desc->bDescriptorType != USB_DT_ENDPOINT)
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !is_enabled (dum))
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* drivers must not request bad settings, since lower levels
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (hardware or its drivers) may not check.  some endpoints
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't do iso, many have maxpacket limitations, etc.
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since this "hardware" driver is here to help debugging, we
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * have some extra sanity checks.  (there could be more though,
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially for "ep9out" style fixed function ones.)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = -EINVAL;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (desc->bmAttributes & 0x03) {
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_BULK:
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int")) {
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max == 512)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* conserve return statements */
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (max) {
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case 8: case 16: case 32: case 64:
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we'll fake any legal size */
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			default:
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_LOW:
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto done;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_INT:
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 64)
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 8)
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_ENDPOINT_XFER_ISOC:
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strstr (ep->ep.name, "-bulk")
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				|| strstr (ep->ep.name, "-int"))
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* real hardware might not handle all packet sizes */
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dum->gadget.speed) {
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_HIGH:
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1024)
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_SPEED_FULL:
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (max <= 1023)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* save a return statement */
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto done;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* few chips support control except on ep0 */
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_ep->maxpacket = max;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = desc;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
423d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_ep->name,
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		desc->bEndpointAddress & 0x0f,
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *val;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (desc->bmAttributes & 0x03) {
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_ENDPOINT_XFER_BULK: val = "bulk"; break;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_ENDPOINT_XFER_ISOC: val = "iso"; break;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_ENDPOINT_XFER_INT: val = "intr"; break;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 default: val = "ctrl"; break;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; val; }),
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		max);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* at this point real hardware should be NAKing transfers
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to that endpoint, until a buffer is queued to it.
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_disable (struct usb_ep *_ep)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !ep->desc || _ep->name == ep0name)
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep->desc = NULL;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = 0;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nuke (dum, ep);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
462d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_request *
46755016f10e31bb15b85d8c500f979dfdceb37d548Al Virodummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4767039f4224d4e40b06308d5c1a97427af1a142459Eric Sesterhenn	req = kzalloc(sizeof(*req), mem_flags);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!req)
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&req->queue);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &req->req;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WARN_ON (!list_empty (&req->queue));
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree (req);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfifo_complete (struct usb_ep *ep, struct usb_request *req)
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5045db539e49fc7471e23bf3c94ca304f008cb7b7f3Olav Kongasdummy_queue (struct usb_ep *_ep, struct usb_request *_req,
50555016f10e31bb15b85d8c500f979dfdceb37d548Al Viro		gfp_t mem_flags)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	req = usb_request_to_dummy_request (_req);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_req || !list_empty (&req->queue) || !_req->complete)
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || (!ep->desc && _ep->name != ep0name))
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !is_enabled (dum))
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
525d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep, _req, _ep->name, _req->length, _req->buf);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->status = -EINPROGRESS;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	_req->actual = 0;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* implement an emulated single-request FIFO */
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&dum->fifo_req.queue) &&
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_empty (&ep->queue) &&
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->length <= FIFO_SIZE) {
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req = &dum->fifo_req;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req = *_req;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.buf = dum->fifo_buf;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy (dum->fifo_buf, _req->buf, _req->length);
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.context = dum;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		req->req.complete = fifo_complete;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->actual = _req->length;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->status = 0;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail (&req->queue, &ep->queue);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* real hardware would likely enable transfers here, in case
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it'd been left NAKing.
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval = -EINVAL;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req = NULL;
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep || !_req)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
576b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_save (flags);
577b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_lock (&dum->lock);
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (&req->req == _req) {
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			_req->status = -ECONNRESET;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = 0;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
586b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	spin_unlock (&dum->lock);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval == 0) {
589d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		dev_dbg (udc_dev(dum),
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"dequeued req %p from %s, len %d buf %p\n",
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req, _ep->name, _req->length, _req->buf);
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		_req->complete (_ep, _req);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
594b4dbda1a22d236842b75be4e2679a96a4fd72632Alan Stern	local_irq_restore (flags);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdummy_set_halt (struct usb_ep *_ep, int value)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_ep		*ep;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!_ep)
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ep = usb_ep_to_dummy_ep (_ep);
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = ep_to_dummy (ep);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver)
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ESHUTDOWN;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!value)
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 0;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			!list_empty (&ep->queue))
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = 1;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME clear emulated data toggle too */
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_ep_ops dummy_ep_ops = {
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable		= dummy_enable,
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable	= dummy_disable,
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.alloc_request	= dummy_alloc_request,
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.free_request	= dummy_free_request,
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.queue		= dummy_queue,
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	= dummy_dequeue,
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_halt	= dummy_set_halt,
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* there are both host and device side versions of this call ... */
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_g_get_frame (struct usb_gadget *_gadget)
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timeval	tv;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do_gettimeofday (&tv);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tv.tv_usec / 1000;
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_wakeup (struct usb_gadget *_gadget)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = gadget_to_dummy (_gadget);
650391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE)
6515742b0c95026c817d9c266174ca39a909e8d38caAlan Stern				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
653391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
654391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ENOLINK;
655391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
656391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			 dum->rh_state != DUMMY_RH_SUSPENDED)
657391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -EIO;
658391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
659391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* FIXME: What if the root hub is suspended but the port isn't? */
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* hub notices our request, issues downstream resume, etc */
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->resuming = 1;
663f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->re_timeout = jiffies + msecs_to_jiffies(20);
664685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = gadget_to_dummy (_gadget);
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (value)
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
680f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Sternstatic int dummy_pullup (struct usb_gadget *_gadget, int value)
681f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern{
682f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	struct dummy	*dum;
683f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	unsigned long	flags;
684f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
685f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum = gadget_to_dummy (_gadget);
686f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
687f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = (value != 0);
688f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
689f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
690685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
691685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
692f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	return 0;
693f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern}
694f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_gadget_ops dummy_ops = {
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame	= dummy_g_get_frame,
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.wakeup		= dummy_wakeup,
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_selfpowered = dummy_set_selfpowered,
699f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	.pullup		= dummy_pullup,
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "function" sysfs attribute */
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
70610523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_function (struct device *dev, struct device_attribute *attr, char *buf)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = gadget_dev_to_dummy (dev);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->driver || !dum->driver->function)
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
714cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternstatic DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver registration/unregistration.
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is basically hardware-specific; there's usually only one real USB
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device (not host) controller since that's how USB devices are intended
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to work.  So most implementations of these api calls will rely on the
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fact that only one driver will ever bind to the hardware.  But curious
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware can be built with discrete components, so the gadget API doesn't
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * require that assumption.
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For this emulator, it might be convenient to create a usb slave device
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each driver that registers:  just add to a big root hub.
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_register_driver (struct usb_gadget_driver *driver)
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = the_controller;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval, i;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum)
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->driver)
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
7426bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell	if (!driver->bind || !driver->setup
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			|| driver->speed == USB_SPEED_UNKNOWN)
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SLAVE side init ... the layer above hardware, which
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * can't enumerate without help from the driver we're binding.
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7505742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->devstatus = 0;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&dum->gadget.ep_list);
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.name = ep_name [i];
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.ops = &dummy_ep_ops;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->halted = ep->already_seen = ep->setup_stage = 0;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->ep.maxpacket = ~0;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->last_io = jiffies;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->gadget = &dum->gadget;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->desc = NULL;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		INIT_LIST_HEAD (&ep->queue);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->gadget.ep0 = &dum->ep [0].ep;
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->ep [0].ep.maxpacket = 64;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del_init (&dum->ep [0].ep.ep_list);
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&dum->fifo_req.queue);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = driver;
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->gadget.dev.driver = &driver->driver;
777d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
779efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if ((retval = driver->bind (&dum->gadget)) != 0)
780efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern		goto err_bind_gadget;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->driver.bus = dum->gadget.dev.parent->bus;
783efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if ((retval = driver_register (&driver->driver)) != 0)
784efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern		goto err_register;
785efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if ((retval = device_bind_driver (&dum->gadget.dev)) != 0)
786efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern		goto err_bind_driver;
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* khubd will enumerate this in a while */
789f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irq (&dum->lock);
790f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 1;
791f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
792f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irq (&dum->lock);
793685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
794685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
796efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern
797efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Sternerr_bind_driver:
798efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	driver_unregister (&driver->driver);
799efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Sternerr_register:
8006bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell	if (driver->unbind)
8016bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell		driver->unbind (&dum->gadget);
802efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	spin_lock_irq (&dum->lock);
803efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	dum->pullup = 0;
804efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	set_link_state (dum);
805efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	spin_unlock_irq (&dum->lock);
806efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Sternerr_bind_gadget:
807efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	dum->driver = NULL;
808efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	dum->gadget.dev.driver = NULL;
809efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	return retval;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_register_driver);
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsusb_gadget_unregister_driver (struct usb_gadget_driver *driver)
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum = the_controller;
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum)
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
8216bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell	if (!driver || driver != dum->driver || !driver->unbind)
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
824d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			driver->driver.name);
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
828f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 0;
829f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver->unbind (&dum->gadget);
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->driver = NULL;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_release_driver (&dum->gadget.dev);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_unregister (&driver->driver);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
838f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_lock_irqsave (&dum->lock, flags);
839f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	dum->pullup = 0;
840f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	set_link_state (dum);
841f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	spin_unlock_irqrestore (&dum->lock, flags);
842f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
843685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (usb_gadget_unregister_driver);
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_enabled
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
850cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern/* just declare this in any driver that really need it */
851cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Sternextern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
852cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOSYS;
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL (net2280_set_fifo_mode);
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
859d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
860d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* The gadget structure is stored inside the hcd structure and will be
861d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * released along with it. */
862d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
863d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_gadget_release (struct device *dev)
864d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
865d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	struct dummy	*dum = gadget_dev_to_dummy (dev);
866d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
8671720058343fa43a1a25bfad9e62ea06e7e9743b6Alan Stern	usb_put_hcd (dummy_to_hcd (dum));
868d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
869d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
8708364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_probe (struct platform_device *pdev)
871d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
872d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	struct dummy	*dum = the_controller;
873d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	int		rc;
874d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
875d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.name = gadget_name;
876d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.ops = &dummy_ops;
877d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.is_dualspeed = 1;
878d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
879d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	/* maybe claim OTG support, though we won't complete HNP */
880d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
881d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
882d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	strcpy (dum->gadget.dev.bus_id, "gadget");
8838364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dum->gadget.dev.parent = &pdev->dev;
884d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	dum->gadget.dev.release = dummy_gadget_release;
885d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	rc = device_register (&dum->gadget.dev);
886d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (rc < 0)
887d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		return rc;
888d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
8891720058343fa43a1a25bfad9e62ea06e7e9743b6Alan Stern	usb_get_hcd (dummy_to_hcd (dum));
890d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
8918364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	platform_set_drvdata (pdev, dum);
892efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
893efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	if (rc < 0)
894efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern		device_unregister (&dum->gadget.dev);
895d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return rc;
896d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
897d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
8988364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_remove (struct platform_device *pdev)
899d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern{
9008364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	struct dummy	*dum = platform_get_drvdata (pdev);
901d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9028364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	platform_set_drvdata (pdev, NULL);
903d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_remove_file (&dum->gadget.dev, &dev_attr_function);
904d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	device_unregister (&dum->gadget.dev);
905d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
906d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern}
907d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9088364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
909391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
9108364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	struct dummy	*dum = platform_get_drvdata(pdev);
911391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
9128364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
913391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
914391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->udc_suspended = 1;
915391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
916391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
917391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
9188364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	pdev->dev.power.power_state = state;
919391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
920391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
921391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
922391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
9238364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_udc_resume (struct platform_device *pdev)
924391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
9258364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	struct dummy	*dum = platform_get_drvdata(pdev);
926391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
9278364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
928391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
929391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->udc_suspended = 0;
930391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
931391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
932391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
9338364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	pdev->dev.power.power_state = PMSG_ON;
934391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
935391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
936391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
937391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
9383ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_udc_driver = {
939d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_udc_probe,
940d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_udc_remove,
941391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_udc_suspend,
942391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_udc_resume,
9433ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
9443ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) gadget_name,
9453ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
9463ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
947d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
948d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MASTER/HOST SIDE DRIVER
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this uses the hcd framework to hook up to host side drivers.
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its root hub will only have one device, otherwise it acts like
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a normal host controller.
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when urbs are queued, they're just stuck on a list that we
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scan in a timer callback.  that callback connects writes from
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the host with reads from the device, and so on, based on the
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb 2.0 rules.
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_urb_enqueue (
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd			*hcd,
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb			*urb,
96655016f10e31bb15b85d8c500f979dfdceb37d548Al Viro	gfp_t				mem_flags
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp	*urbp;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
971e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urb->transfer_buffer && urb->transfer_buffer_length)
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp = kmalloc (sizeof *urbp, mem_flags);
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!urbp)
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urbp->urb = urb;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
983e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_link_urb_to_ep(hcd, urb);
984e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	if (rc) {
985e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		kfree(urbp);
986e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		goto done;
987e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	}
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->udev) {
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->udev = urb->dev;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_get_dev (dum->udev);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (unlikely (dum->udev != urb->dev))
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum), "usb_device address has changed!\n");
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail (&urbp->urbp_list, &dum->urbp_list);
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	urb->hcpriv = urbp;
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->error_count = 1;		/* mark as a new urb */
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* kick the scheduler, it'll do the rest */
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!timer_pending (&dum->timer))
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mod_timer (&dum->timer, jiffies + 1);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
1005e9df41c5c5899259541dc928872cad4d07b82076Alan Stern done:
1006e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1009e9df41c5c5899259541dc928872cad4d07b82076Alan Sternstatic int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1011391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy	*dum;
1012391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	unsigned long	flags;
1013e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	int		rc;
1014391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1015391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	/* giveback happens automatically in timer callback,
1016391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	 * so make sure the callback happens */
1017391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum = hcd_to_dummy (hcd);
1018391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irqsave (&dum->lock, flags);
1019e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1020e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
1021e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
1022e9df41c5c5899259541dc928872cad4d07b82076Alan Stern			!list_empty(&dum->urbp_list))
1023391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		mod_timer (&dum->timer, jiffies);
1024e9df41c5c5899259541dc928872cad4d07b82076Alan Stern
1025391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irqrestore (&dum->lock, flags);
1026e9df41c5c5899259541dc928872cad4d07b82076Alan Stern	return rc;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void maybe_set_status (struct urb *urb, int status)
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock (&urb->lock);
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (urb->status == -EINPROGRESS)
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->status = status;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock (&urb->lock);
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transfer up to a frame's worth; caller must own lock */
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstransfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy_request	*req;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstop:
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if there's no request queued, the device is NAKing; return */
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (req, &ep->queue, queue) {
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned	host_len, dev_len, len;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		is_short, to_host;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int		rescan = 0;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* 1..N packets of ep->ep.maxpacket each ... the last one
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * may be short (including zero length).
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * writer can send a zlp explicitly (length 0) or implicitly
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (length mod maxpacket zero, and 'zero' flag); they always
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * terminate reads.
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		host_len = urb->transfer_buffer_length - urb->actual_length;
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_len = req->req.length - req->req.actual;
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = min (host_len, dev_len);
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME update emulated data toggle too */
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_host = usb_pipein (urb->pipe);
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely (len == 0))
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = 1;
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char		*ubuf, *rbuf;
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* not enough bandwidth left? */
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (limit < ep->ep.maxpacket && limit < len)
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = min (len, (unsigned) limit);
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len == 0)
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* use an extra pass for the final short packet */
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > ep->ep.maxpacket) {
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rescan = 1;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len -= (len % ep->ep.maxpacket);
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			is_short = (len % ep->ep.maxpacket) != 0;
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* else transfer packet(s) */
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ubuf = urb->transfer_buffer + urb->actual_length;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rbuf = req->req.buf + req->req.actual;
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (to_host)
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (ubuf, rbuf, len);
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy (rbuf, ubuf, len);
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit -= len;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->actual_length += len;
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.actual += len;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* short packets terminate, maybe with overflow/underflow.
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * it's only really an error to write too much.
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * partially filling a buffer optionally blocks queue advances
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * (so completion handlers can clean up the queue) but we don't
1102b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern		 * need to emulate such data-in-flight.
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (is_short) {
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (host_len == dev_len) {
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (to_host) {
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (dev_len > host_len)
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, -EOVERFLOW);
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
1113b0d9efba3ec53468984aecef8eeaf079089f2e5aAlan Stern					maybe_set_status (urb, 0);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (!to_host) {
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (host_len > dev_len)
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = -EOVERFLOW;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					req->req.status = 0;
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* many requests terminate without a short packet */
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (req->req.length == req->req.actual
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !req->req.zero)
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = 0;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (urb->transfer_buffer_length == urb->actual_length
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					&& !(urb->transfer_flags
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						& URB_ZERO_PACKET)) {
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* device side completion --> continuable */
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (req->req.status != -EINPROGRESS) {
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del_init (&req->queue);
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock (&dum->lock);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			req->req.complete (&ep->ep, &req->req);
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock (&dum->lock);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* requests might have been unlinked... */
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rescan = 1;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* host side completion --> terminate */
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status != -EINPROGRESS)
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* rescan to continue with any other queued i/o */
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rescan)
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto top;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	limit = ep->ep.maxpacket;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dum->gadget.speed == USB_SPEED_HIGH) {
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int	tmp;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* high bandwidth mode */
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp = (tmp >> 11) & 0x03;
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmp *= 8 /* applies to entire frame */;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit += limit * tmp;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return limit;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define is_active(dum)	((dum->port_status & \
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			USB_PORT_STAT_SUSPEND)) \
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		i;
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!is_active (dum))
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((address & ~USB_DIR_IN) == 0)
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return &dum->ep [0];
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep	*ep = &dum->ep [i];
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep->desc)
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->desc->bEndpointAddress == address)
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ep;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef is_active
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Dev_InRequest	(Dev_Request | USB_DIR_IN)
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Intf_InRequest	(Intf_Request | USB_DIR_IN)
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_Request	(USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define Ep_InRequest	(Ep_Request | USB_DIR_IN)
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drive both sides of the transfers; looks like irq handlers to
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * both drivers except the callbacks aren't in_irq().
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_timer (unsigned long _dum)
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum = (struct dummy *) _dum;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp, *tmp;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			limit, total;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			i;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* simplistic model for one frame's bandwidth */
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (dum->gadget.speed) {
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_LOW:
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 8/*bytes*/ * 12/*packets*/;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_FULL:
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 64/*bytes*/ * 19/*packets*/;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_SPEED_HIGH:
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum), "bogus device speed\n");
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME if HZ != 1000 this will probably misbehave ... */
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* look at each urb queued by the host side driver */
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dum->udev) {
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err (dummy_dev(dum),
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"timer fired with no URBs pending?\n");
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore (&dum->lock, flags);
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep_name [i])
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->ep [i].already_seen = 0;
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart:
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) {
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct urb		*urb;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_request	*req;
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u8			address;
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct dummy_ep		*ep = NULL;
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int			type;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = urbp->urb;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status != -EINPROGRESS) {
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* likely it was just unlinked */
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
1263391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		} else if (dum->rh_state != DUMMY_RH_RUNNING)
1264391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			continue;
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		type = usb_pipetype (urb->pipe);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* used up this frame's non-periodic bandwidth?
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * FIXME there's infinite bandwidth for control and
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * periodic transfers ... unrealistic.
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (total <= 0 && type == PIPE_BULK)
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* find the gadget's ep for this request (if configured) */
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		address = usb_pipeendpoint (urb->pipe);
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (usb_pipein (urb->pipe))
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			address |= USB_DIR_IN;
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep = find_endpoint(dum, address);
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ep) {
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* set_configuration() disagreement */
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_dbg (dummy_dev(dum),
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"no ep configured for urb %p\n",
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb);
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -EPROTO);
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->already_seen)
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep->already_seen = 1;
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && urb->error_count) {
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 1;	/* a new urb */
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->error_count = 0;
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep->halted && !ep->setup_stage) {
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* NOTE: must not be iso! */
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep->ep.name, urb);
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -EPIPE);
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME make sure both ends agree on maxpacket */
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* handle control requests */
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep == &dum->ep [0] && ep->setup_stage) {
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct usb_ctrlrequest		setup;
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int				value = 1;
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct dummy_ep			*ep2;
1309cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			unsigned			w_index;
1310cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			unsigned			w_value;
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			setup = *(struct usb_ctrlrequest*) urb->setup_packet;
1313cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			w_index = le16_to_cpu(setup.wIndex);
1314cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			w_value = le16_to_cpu(setup.wValue);
1315cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			if (le16_to_cpu(setup.wLength) !=
1316cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					urb->transfer_buffer_length) {
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, -EOVERFLOW);
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto return_urb;
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* paranoia, in case of stale queued data */
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_for_each_entry (req, &ep->queue, queue) {
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				list_del_init (&req->queue);
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.status = -EOVERFLOW;
1325d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "stale req = %p\n",
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						req);
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				req->req.complete (&ep->ep, &req->req);
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ep->already_seen = 0;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto restart;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver never sees set_address or operations
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * on standard feature flags.  some hardware doesn't
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * even expose them.
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->setup_stage = 0;
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->halted = 0;
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			switch (setup.bRequest) {
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_SET_ADDRESS:
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType != Dev_Request)
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
1346cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern				dum->address = w_value;
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, 0);
1348d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern				dev_dbg (udc_dev(dum), "set_address = %d\n",
1349cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern						w_value);
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = 0;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_SET_FEATURE:
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_Request) {
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
1355cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					switch (w_value) {
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					case USB_DEVICE_REMOTE_WAKEUP:
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
13585742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_B_HNP_ENABLE:
13595742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.b_hnp_enable = 1;
13605742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13615742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_A_HNP_SUPPORT:
13625742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.a_hnp_support = 1;
13635742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13645742b0c95026c817d9c266174ca39a909e8d38caAlan Stern					case USB_DEVICE_A_ALT_HNP_SUPPORT:
13655742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						dum->gadget.a_alt_hnp_support
13665742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							= 1;
13675742b0c95026c817d9c266174ca39a909e8d38caAlan Stern						break;
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					default:
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (value == 0) {
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						dum->devstatus |=
1373cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern							(1 << w_value);
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						maybe_set_status (urb, 0);
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else if (setup.bRequestType == Ep_Request) {
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint halt
1379cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					ep2 = find_endpoint (dum, w_index);
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (!ep2) {
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep2->halted = 1;
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_CLEAR_FEATURE:
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_Request) {
1391cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					switch (w_value) {
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					case USB_DEVICE_REMOTE_WAKEUP:
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						dum->devstatus &= ~(1 <<
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							USB_DEVICE_REMOTE_WAKEUP);
13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = 0;
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						maybe_set_status (urb, 0);
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					default:
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else if (setup.bRequestType == Ep_Request) {
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint halt
1404cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern					ep2 = find_endpoint (dum, w_index);
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (!ep2) {
14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value = -EOPNOTSUPP;
14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						break;
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ep2->halted = 0;
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case USB_REQ_GET_STATUS:
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (setup.bRequestType == Dev_InRequest
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						|| setup.bRequestType
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							== Intf_InRequest
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						|| setup.bRequestType
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							== Ep_InRequest
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						) {
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					char *buf;
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// device: remote wakeup, selfpowered
14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// interface: nothing
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					// endpoint: halt
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					buf = (char *)urb->transfer_buffer;
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (urb->transfer_buffer_length > 0) {
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						if (setup.bRequestType ==
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								Ep_InRequest) {
1430cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern	ep2 = find_endpoint (dum, w_index);
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ep2) {
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		value = -EOPNOTSUPP;
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf [0] = ep2->halted;
14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						} else if (setup.bRequestType ==
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								Dev_InRequest) {
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							buf [0] = (u8)
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								dum->devstatus;
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						} else
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							buf [0] = 0;
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (urb->transfer_buffer_length > 1)
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						buf [1] = 0;
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					urb->actual_length = min (2,
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						urb->transfer_buffer_length);
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					value = 0;
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					maybe_set_status (urb, 0);
14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* gadget driver handles all other requests.  block
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * until setup() returns; no reentrancy issues etc.
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value > 0) {
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_unlock (&dum->lock);
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				value = dum->driver->setup (&dum->gadget,
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						&setup);
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				spin_lock (&dum->lock);
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value >= 0) {
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* no delays (max 64KB data stage) */
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					limit = 64*1024;
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto treat_control_like_bulk;
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* error, see below */
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (value < 0) {
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (value != -EOPNOTSUPP)
1472d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern					dev_dbg (udc_dev(dum),
14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"setup --> %d\n",
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						value);
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				maybe_set_status (urb, -EPIPE);
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				urb->actual_length = 0;
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto return_urb;
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* non-control requests */
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		limit = total;
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (usb_pipetype (urb->pipe)) {
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_ISOCHRONOUS:
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * use urb->iso_frame_desc[i].
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * complete whether or not ep has requests queued.
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * report random errors, to debug drivers.
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			maybe_set_status (urb, -ENOSYS);
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case PIPE_INTERRUPT:
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME is it urb->interval since the last xfer?
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this almost certainly polls too fast.
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			limit = max (limit, periodic_bytes (dum, ep));
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FALLTHROUGH */
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// case PIPE_BULK:  case PIPE_CONTROL:
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		treat_control_like_bulk:
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->last_io = jiffies;
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			total = transfer (dum, urb, ep, limit);
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* incomplete transfer? */
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb->status == -EINPROGRESS)
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreturn_urb:
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del (&urbp->urbp_list);
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree (urbp);
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ep)
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ep->already_seen = ep->setup_stage = 0;
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1520e9df41c5c5899259541dc928872cad4d07b82076Alan Stern		usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock (&dum->lock);
152228431146993e0ab3a2a592af8541543fe0cc2c8eAl Viro		usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock (&dum->lock);
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto restart;
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1528391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if (list_empty (&dum->urbp_list)) {
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_put_dev (dum->udev);
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dum->udev = NULL;
1531391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	} else if (dum->rh_state == DUMMY_RH_RUNNING) {
1532391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		/* want a 1 msec delay here */
1533391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PORT_C_MASK \
1542c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	((USB_PORT_STAT_C_CONNECTION \
1543c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_ENABLE \
1544c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_SUSPEND \
1545c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_OVERCURRENT \
1546c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern	| USB_PORT_STAT_C_RESET) << 16)
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_status (struct usb_hcd *hcd, char *buf)
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
1552391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	int			retval = 0;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
15573cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
1558391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		goto done;
1559f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1560f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
1561f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1562f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		dum->port_status &= ~USB_PORT_STAT_SUSPEND;
1563f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		set_link_state (dum);
1564f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern	}
1565f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1566391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	if ((dum->port_status & PORT_C_MASK) != 0) {
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*buf = (1 << 1);
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
1569391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern				dum->port_status);
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 1;
1571391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		if (dum->rh_state == DUMMY_RH_SUSPENDED)
1572391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			usb_hcd_resume_root_hub (hcd);
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1574391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Sterndone:
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshub_descriptor (struct usb_hub_descriptor *desc)
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset (desc, 0, sizeof *desc);
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescriptorType = 0x29;
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bDescLength = 9;
1585cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern	desc->wHubCharacteristics = (__force __u16)
1586cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern			(__constant_cpu_to_le16 (0x0001));
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bNbrPorts = 1;
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bitmap [0] = 0xff;
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc->bitmap [1] = 0xff;
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_hub_control (
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd	*hcd,
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		typeReq,
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wValue,
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wIndex,
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char		*buf,
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16		wLength
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds) {
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy	*dum;
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int		retval = 0;
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long	flags;
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16043cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
1605391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern		return -ETIMEDOUT;
1606391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (typeReq) {
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearHubFeature:
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ClearPortFeature:
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
1615c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			if (dum->port_status & USB_PORT_STAT_SUSPEND) {
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* 20msec resume signaling */
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->resuming = 1;
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->re_timeout = jiffies +
1619f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						msecs_to_jiffies(20);
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_POWER:
1623f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->port_status & USB_PORT_STAT_POWER)
1624f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				dev_dbg (dummy_dev(dum), "power-off\n");
1625f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dum->port_status &= ~(1 << wValue);
1628f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			set_link_state (dum);
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubDescriptor:
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hub_descriptor ((struct usb_hub_descriptor *) buf);
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetHubStatus:
1635cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		*(__le32 *) buf = __constant_cpu_to_le32 (0);
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GetPortStatus:
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (wIndex != 1)
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retval = -EPIPE;
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* whoever resets or resumes must GetPortStatus to
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * complete it!!
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1644f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if (dum->resuming &&
1645f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				time_after_eq (jiffies, dum->re_timeout)) {
1646c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1647c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1649f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
1650f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				time_after_eq (jiffies, dum->re_timeout)) {
1651c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
1652c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern			dum->port_status &= ~USB_PORT_STAT_RESET;
1653f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->pullup) {
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->port_status |= USB_PORT_STAT_ENABLE;
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* give it the best speed we agree on */
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->gadget.speed = dum->driver->speed;
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dum->gadget.ep0->maxpacket = 64;
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				switch (dum->gadget.speed) {
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case USB_SPEED_HIGH:
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->port_status |=
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						USB_PORT_STAT_HIGH_SPEED;
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case USB_SPEED_LOW:
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->gadget.ep0->maxpacket = 8;
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->port_status |=
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						USB_PORT_STAT_LOW_SPEED;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				default:
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dum->gadget.speed = USB_SPEED_FULL;
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1674f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		set_link_state (dum);
1675cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
1676cc095b0b5b653dca3e106710a72ba28b5bb7456bAlan Stern		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetHubFeature:
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SetPortFeature:
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (wValue) {
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_SUSPEND:
1684f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if (dum->active) {
1685c2db8b5e5692a6f35913a829607ee6efde3c7cbdAlan Stern				dum->port_status |= USB_PORT_STAT_SUSPEND;
1686f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern
1687f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				/* HNP would happen here; for now we
1688f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 * assume b_bus_req is always true.
1689f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				 */
1690f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				set_link_state (dum);
1691f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				if (((1 << USB_DEVICE_B_HNP_ENABLE)
1692f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern						& dum->devstatus) != 0)
1693f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					dev_dbg (dummy_dev(dum),
16945742b0c95026c817d9c266174ca39a909e8d38caAlan Stern							"no HNP yet!\n");
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1697f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern		case USB_PORT_FEAT_POWER:
1698f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status |= USB_PORT_STAT_POWER;
1699f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			set_link_state (dum);
1700f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			break;
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case USB_PORT_FEAT_RESET:
1702f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* if it's already enabled, disable */
1703f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			dum->port_status &= ~(USB_PORT_STAT_ENABLE
1704f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_LOW_SPEED
1705f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern					| USB_PORT_STAT_HIGH_SPEED);
1706391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern			dum->devstatus = 0;
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* 50msec reset signaling */
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dum->re_timeout = jiffies + msecs_to_jiffies(50);
1709f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			/* FALLS THROUGH */
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
1711f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
1712f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				dum->port_status |= (1 << wValue);
1713f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern				set_link_state (dum);
1714f1c39fad7d1bbea31744138cd3a532ff346cd4abAlan Stern			}
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg (dummy_dev(dum),
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"hub control req%04x v%04x i%04x l%d\n",
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			typeReq, wValue, wIndex, wLength);
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* "protocol stall" on error */
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = -EPIPE;
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
1727685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern
1728685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	if ((dum->port_status & PORT_C_MASK) != 0)
1729685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern		usb_hcd_poll_rh_status (hcd);
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17330c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_suspend (struct usb_hcd *hcd)
1734391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1735391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy *dum = hcd_to_dummy (hcd);
1736391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
17373cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__);
17383cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
1739391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
1740391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->rh_state = DUMMY_RH_SUSPENDED;
1741391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	set_link_state (dum);
17423cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd->state = HC_STATE_SUSPENDED;
1743391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
1744391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1745391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1746391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
17470c0382e32d46f606951010b202382be14d180a17Alan Sternstatic int dummy_bus_resume (struct usb_hcd *hcd)
1748391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1749391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct dummy *dum = hcd_to_dummy (hcd);
17503cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int rc = 0;
17513cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern
17523cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__);
1753391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
1754391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_lock_irq (&dum->lock);
17553cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
1756cfa59dab27d1b282886e7772a8f9548236883892Alan Stern		rc = -ESHUTDOWN;
17573cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else {
17583cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		dum->rh_state = DUMMY_RH_RUNNING;
17593cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		set_link_state (dum);
17603cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		if (!list_empty(&dum->urbp_list))
17613cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern			mod_timer (&dum->timer, jiffies);
17623cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		hcd->state = HC_STATE_RUNNING;
17633cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	}
1764391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	spin_unlock_irq (&dum->lock);
17653cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
1766391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ssize_t
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_urb (char *buf, size_t size, struct urb *urb)
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ep = usb_pipeendpoint (urb->pipe);
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf (buf, size,
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"urb/%p %s ep%d%s%s len %d/%d\n",
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb,
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s;
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (urb->dev->speed) {
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_LOW:	s = "ls"; break;
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_FULL:	s = "fs"; break;
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case USB_SPEED_HIGH:	s = "hs"; break;
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 default:		s = "?"; break;
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 }; s; }),
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		({ char *s; \
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 switch (usb_pipetype (urb->pipe)) { \
17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_CONTROL:	s = ""; break; \
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_BULK:	s = "-bulk"; break; \
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 case PIPE_INTERRUPT:	s = "-int"; break; \
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 default: 		s = "-iso"; break; \
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}; s;}),
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->actual_length, urb->transfer_buffer_length);
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
179710523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoushow_urbs (struct device *dev, struct device_attribute *attr, char *buf)
17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd = dev_get_drvdata (dev);
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum = hcd_to_dummy (hcd);
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urbp		*urbp;
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t			size = 0;
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long		flags;
18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&dum->lock, flags);
18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size_t		temp;
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf += temp;
18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += temp;
18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&dum->lock, flags);
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return size;
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_start (struct usb_hcd *hcd)
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * MASTER side init ... we emulate a root hub that'll only ever
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * talk to one device (the slave side).  Also appears in sysfs,
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * just like more familiar pci-based HCDs.
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init (&dum->lock);
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer (&dum->timer);
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->timer.function = dummy_timer;
18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum->timer.data = (unsigned long) dum;
1834391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	dum->rh_state = DUMMY_RH_RUNNING;
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD (&dum->urbp_list);
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1838bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern	/* only show a low-power port: just 8mA */
1839bc96c0ad1ed0c938fefc0423aa99f086c5a2a1eaAlan Stern	hcd->power_budget = 8;
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hcd->state = HC_STATE_RUNNING;
1841685eb93f086eb15d9fb1e82c7400fd750f564640Alan Stern	hcd->uses_new_polling = 1;
18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18435742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#ifdef CONFIG_USB_OTG
18445742b0c95026c817d9c266174ca39a909e8d38caAlan Stern	hcd->self.otg_port = 1;
18455742b0c95026c817d9c266174ca39a909e8d38caAlan Stern#endif
18465742b0c95026c817d9c266174ca39a909e8d38caAlan Stern
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
1848efd54a364121f61b2050b1df5ecb1b8329c4eabaAlan Stern	return device_create_file (dummy_dev(dum), &dev_attr_urbs);
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dummy_stop (struct usb_hcd *hcd)
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dummy		*dum;
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dum = hcd_to_dummy (hcd);
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_gadget_unregister_driver (dum->driver);
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_info (dummy_dev(dum), "stopped\n");
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_h_get_frame (struct usb_hcd *hcd)
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return dummy_g_get_frame (NULL);
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct hc_driver dummy_hcd = {
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.description =		(char *) driver_name,
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.product_desc =		"Dummy host controller",
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hcd_priv_size =	sizeof(struct dummy),
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flags =		HCD_USB2,
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start =		dummy_start,
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop =			dummy_stop,
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_enqueue = 		dummy_urb_enqueue,
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.urb_dequeue = 		dummy_urb_dequeue,
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_frame_number = 	dummy_h_get_frame,
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_status_data = 	dummy_hub_status,
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.hub_control = 		dummy_hub_control,
18860c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_suspend =		dummy_bus_suspend,
18870c0382e32d46f606951010b202382be14d180a17Alan Stern	.bus_resume =		dummy_bus_resume,
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18908364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_probe(struct platform_device *pdev)
18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd;
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int			retval;
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18958364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18978364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, pdev->dev.bus_id);
18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!hcd)
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	the_controller = hcd_to_dummy (hcd);
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = usb_add_hcd(hcd, 0, 0);
19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval != 0) {
19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		usb_put_hcd (hcd);
19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		the_controller = NULL;
19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19108364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_remove (struct platform_device *pdev)
19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_hcd		*hcd;
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19148364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	hcd = platform_get_drvdata (pdev);
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_remove_hcd (hcd);
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_put_hcd (hcd);
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	the_controller = NULL;
1918d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return 0;
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19218364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
1922391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1923391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
19243cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	struct dummy		*dum;
19253cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	int			rc = 0;
1926391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
19278364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
1928391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
19293cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
19303cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	dum = hcd_to_dummy (hcd);
19313cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	if (dum->rh_state == DUMMY_RH_RUNNING) {
19323cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
19333cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		rc = -EBUSY;
19343cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	} else
19353cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
19363cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	return rc;
1937391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1938391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
19398364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Sternstatic int dummy_hcd_resume (struct platform_device *pdev)
1940391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern{
1941391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	struct usb_hcd		*hcd;
1942391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
19438364d6b0be2dbbf162c6aea79615b5025a0d67c2Alan Stern	dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
1944391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
19453cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	hcd = platform_get_drvdata (pdev);
19463cf0a22e8b1b3f44288db773d315e72e89d51c4cAlan Stern	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
1947391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	usb_hcd_poll_rh_status (hcd);
1948391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	return 0;
1949391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern}
1950391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern
19513ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver dummy_hcd_driver = {
1952d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.probe		= dummy_hcd_probe,
1953d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.remove		= dummy_hcd_remove,
1954391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.suspend	= dummy_hcd_suspend,
1955391eca9d8892a940ff8dbfee2ca78942e05c2d37Alan Stern	.resume		= dummy_hcd_resume,
19563ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
19573ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= (char *) driver_name,
19583ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.owner	= THIS_MODULE,
19593ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
1960d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1962d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/*-------------------------------------------------------------------------*/
19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1964d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern/* These don't need to do anything because the pdev structures are
1965d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern * statically allocated. */
1966d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
1967d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_udc_release (struct device *dev) {}
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1969d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic void
1970d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sterndummy_hcd_release (struct device *dev) {}
1971d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
1972d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct platform_device		the_udc_pdev = {
1973d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) gadget_name,
1974d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.id		= -1,
1975d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.dev		= {
1976d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		.release	= dummy_udc_release,
1977d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	},
1978d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1980d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternstatic struct platform_device		the_hcd_pdev = {
1981d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.name		= (char *) driver_name,
1982d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.id		= -1,
1983d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	.dev		= {
1984d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		.release	= dummy_hcd_release,
1985d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	},
1986d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern};
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init (void)
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int	retval;
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (usb_disabled ())
19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1994d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
19953ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	retval = platform_driver_register (&dummy_hcd_driver);
1996d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
1998d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
19993ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	retval = platform_driver_register (&dummy_udc_driver);
2000d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2001d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc_driver;
2002d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2003d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = platform_device_register (&the_hcd_pdev);
2004d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2005d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_hcd;
2006d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2007d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	retval = platform_device_register (&the_udc_pdev);
2008d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	if (retval < 0)
2009d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern		goto err_register_udc;
2010d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	return retval;
2011d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern
2012d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc:
2013d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_hcd_pdev);
2014d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_hcd:
20153ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_driver_unregister (&dummy_udc_driver);
2016d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Sternerr_register_udc_driver:
20173ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_driver_unregister (&dummy_hcd_driver);
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (init);
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit cleanup (void)
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2024d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_udc_pdev);
2025d9b762510c186584a6be0d3ece03e8a4b2ac13a8Alan Stern	platform_device_unregister (&the_hcd_pdev);
20263ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_driver_unregister (&dummy_udc_driver);
20273ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_driver_unregister (&dummy_hcd_driver);
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (cleanup);
2030